procfs-guide.xml writing_usb_driver.xml networking.xml \
kernel-api.xml filesystems.xml lsm.xml usb.xml \
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
- genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml
+ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
+ mac80211.xml
###
# The build process is as follows (targets):
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="mac80211-developers-guide">
+ <bookinfo>
+ <title>The mac80211 subsystem for kernel developers</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Johannes</firstname>
+ <surname>Berg</surname>
+ <affiliation>
+ <address><email>johannes@sipsolutions.net</email></address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2007</year>
+ <year>2008</year>
+ <holder>Johannes Berg</holder>
+ </copyright>
+
+ <legalnotice>
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License version 2 as published by the Free Software Foundation.
+ </para>
+
+ <para>
+ This documentation 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.
+ </para>
+
+ <para>
+ You should have received a copy of the GNU General Public
+ License along with this documentation; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+
+ <abstract>
+!Pinclude/net/mac80211.h Introduction
+!Pinclude/net/mac80211.h Warning
+ </abstract>
+ </bookinfo>
+
+ <toc></toc>
+
+<!--
+Generally, this document shall be ordered by increasing complexity.
+It is important to note that readers should be able to read only
+the first few sections to get a working driver and only advanced
+usage should require reading the full document.
+-->
+
+ <part>
+ <title>The basic mac80211 driver interface</title>
+ <partintro>
+ <para>
+ You should read and understand the information contained
+ within this part of the book while implementing a driver.
+ In some chapters, advanced usage is noted, that may be
+ skipped at first.
+ </para>
+ <para>
+ This part of the book only covers station and monitor mode
+ functionality, additional information required to implement
+ the other modes is covered in the second part of the book.
+ </para>
+ </partintro>
+
+ <chapter id="basics">
+ <title>Basic hardware handling</title>
+ <para>TBD</para>
+ <para>
+ This chapter shall contain information on getting a hw
+ struct allocated and registered with mac80211.
+ </para>
+ <para>
+ Since it is required to allocate rates/modes before registering
+ a hw struct, this chapter shall also contain information on setting
+ up the rate/mode structs.
+ </para>
+ <para>
+ Additionally, some discussion about the callbacks and
+ the general programming model should be in here, including
+ the definition of ieee80211_ops which will be referred to
+ a lot.
+ </para>
+ <para>
+ Finally, a discussion of hardware capabilities should be done
+ with references to other parts of the book.
+ </para>
+<!-- intentionally multiple !F lines to get proper order -->
+!Finclude/net/mac80211.h ieee80211_hw
+!Finclude/net/mac80211.h ieee80211_hw_flags
+!Finclude/net/mac80211.h SET_IEEE80211_DEV
+!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
+!Finclude/net/mac80211.h ieee80211_ops
+!Finclude/net/mac80211.h ieee80211_alloc_hw
+!Finclude/net/mac80211.h ieee80211_register_hw
+!Finclude/net/mac80211.h ieee80211_get_tx_led_name
+!Finclude/net/mac80211.h ieee80211_get_rx_led_name
+!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
+!Finclude/net/mac80211.h ieee80211_get_radio_led_name
+!Finclude/net/mac80211.h ieee80211_unregister_hw
+!Finclude/net/mac80211.h ieee80211_free_hw
+ </chapter>
+
+ <chapter id="phy-handling">
+ <title>PHY configuration</title>
+ <para>TBD</para>
+ <para>
+ This chapter should describe PHY handling including
+ start/stop callbacks and the various structures used.
+ </para>
+!Finclude/net/mac80211.h ieee80211_conf
+!Finclude/net/mac80211.h ieee80211_conf_flags
+ </chapter>
+
+ <chapter id="iface-handling">
+ <title>Virtual interfaces</title>
+ <para>TBD</para>
+ <para>
+ This chapter should describe virtual interface basics
+ that are relevant to the driver (VLANs, MGMT etc are not.)
+ It should explain the use of the add_iface/remove_iface
+ callbacks as well as the interface configuration callbacks.
+ </para>
+ <para>Things related to AP mode should be discussed there.</para>
+ <para>
+ Things related to supporting multiple interfaces should be
+ in the appropriate chapter, a BIG FAT note should be here about
+ this though and the recommendation to allow only a single
+ interface in STA mode at first!
+ </para>
+!Finclude/net/mac80211.h ieee80211_if_types
+!Finclude/net/mac80211.h ieee80211_if_init_conf
+!Finclude/net/mac80211.h ieee80211_if_conf
+ </chapter>
+
+ <chapter id="rx-tx">
+ <title>Receive and transmit processing</title>
+ <sect1>
+ <title>what should be here</title>
+ <para>TBD</para>
+ <para>
+ This should describe the receive and transmit
+ paths in mac80211/the drivers as well as
+ transmit status handling.
+ </para>
+ </sect1>
+ <sect1>
+ <title>Frame format</title>
+!Pinclude/net/mac80211.h Frame format
+ </sect1>
+ <sect1>
+ <title>Alignment issues</title>
+ <para>TBD</para>
+ </sect1>
+ <sect1>
+ <title>Calling into mac80211 from interrupts</title>
+!Pinclude/net/mac80211.h Calling mac80211 from interrupts
+ </sect1>
+ <sect1>
+ <title>functions/definitions</title>
+!Finclude/net/mac80211.h ieee80211_rx_status
+!Finclude/net/mac80211.h mac80211_rx_flags
+!Finclude/net/mac80211.h ieee80211_tx_control
+!Finclude/net/mac80211.h ieee80211_tx_status_flags
+!Finclude/net/mac80211.h ieee80211_rx
+!Finclude/net/mac80211.h ieee80211_rx_irqsafe
+!Finclude/net/mac80211.h ieee80211_tx_status
+!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
+!Finclude/net/mac80211.h ieee80211_rts_get
+!Finclude/net/mac80211.h ieee80211_rts_duration
+!Finclude/net/mac80211.h ieee80211_ctstoself_get
+!Finclude/net/mac80211.h ieee80211_ctstoself_duration
+!Finclude/net/mac80211.h ieee80211_generic_frame_duration
+!Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb
+!Finclude/net/mac80211.h ieee80211_get_hdrlen
+!Finclude/net/mac80211.h ieee80211_wake_queue
+!Finclude/net/mac80211.h ieee80211_stop_queue
+!Finclude/net/mac80211.h ieee80211_start_queues
+!Finclude/net/mac80211.h ieee80211_stop_queues
+!Finclude/net/mac80211.h ieee80211_wake_queues
+ </sect1>
+ </chapter>
+
+ <chapter id="filters">
+ <title>Frame filtering</title>
+!Pinclude/net/mac80211.h Frame filtering
+!Finclude/net/mac80211.h ieee80211_filter_flags
+ </chapter>
+ </part>
+
+ <part id="advanced">
+ <title>Advanced driver interface</title>
+ <partintro>
+ <para>
+ Information contained within this part of the book is
+ of interest only for advanced interaction of mac80211
+ with drivers to exploit more hardware capabilities and
+ improve performance.
+ </para>
+ </partintro>
+
+ <chapter id="hardware-crypto-offload">
+ <title>Hardware crypto acceleration</title>
+!Pinclude/net/mac80211.h Hardware crypto acceleration
+<!-- intentionally multiple !F lines to get proper order -->
+!Finclude/net/mac80211.h set_key_cmd
+!Finclude/net/mac80211.h ieee80211_key_conf
+!Finclude/net/mac80211.h ieee80211_key_alg
+!Finclude/net/mac80211.h ieee80211_key_flags
+ </chapter>
+
+ <chapter id="qos">
+ <title>Multiple queues and QoS support</title>
+ <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_tx_queue_params
+!Finclude/net/mac80211.h ieee80211_tx_queue_stats_data
+!Finclude/net/mac80211.h ieee80211_tx_queue
+ </chapter>
+
+ <chapter id="AP">
+ <title>Access point mode support</title>
+ <para>TBD</para>
+ <para>Some parts of the if_conf should be discussed here instead</para>
+ <para>
+ Insert notes about VLAN interfaces with hw crypto here or
+ in the hw crypto chapter.
+ </para>
+!Finclude/net/mac80211.h ieee80211_get_buffered_bc
+!Finclude/net/mac80211.h ieee80211_beacon_get
+ </chapter>
+
+ <chapter id="multi-iface">
+ <title>Supporting multiple virtual interfaces</title>
+ <para>TBD</para>
+ <para>
+ Note: WDS with identical MAC address should almost always be OK
+ </para>
+ <para>
+ Insert notes about having multiple virtual interfaces with
+ different MAC addresses here, note which configurations are
+ supported by mac80211, add notes about supporting hw crypto
+ with it.
+ </para>
+ </chapter>
+
+ <chapter id="hardware-scan-offload">
+ <title>Hardware scan offload</title>
+ <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_scan_completed
+ </chapter>
+ </part>
+
+ <part id="rate-control">
+ <title>Rate control interface</title>
+ <partintro>
+ <para>TBD</para>
+ <para>
+ This part of the book describes the rate control algorithm
+ interface and how it relates to mac80211 and drivers.
+ </para>
+ </partintro>
+ <chapter id="dummy">
+ <title>dummy chapter</title>
+ <para>TBD</para>
+ </chapter>
+ </part>
+
+ <part id="internal">
+ <title>Internals</title>
+ <partintro>
+ <para>TBD</para>
+ <para>
+ This part of the book describes mac80211 internals.
+ </para>
+ </partintro>
+
+ <chapter id="key-handling">
+ <title>Key handling</title>
+ <sect1>
+ <title>Key handling basics</title>
+!Pnet/mac80211/key.c Key handling basics
+ </sect1>
+ <sect1>
+ <title>MORE TBD</title>
+ <para>TBD</para>
+ </sect1>
+ </chapter>
+
+ <chapter id="rx-processing">
+ <title>Receive processing</title>
+ <para>TBD</para>
+ </chapter>
+
+ <chapter id="tx-processing">
+ <title>Transmit processing</title>
+ <para>TBD</para>
+ </chapter>
+
+ <chapter id="sta-info">
+ <title>Station info handling</title>
+ <sect1>
+ <title>Programming information</title>
+!Fnet/mac80211/sta_info.h sta_info
+!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
+ </sect1>
+ <sect1>
+ <title>STA information lifetime rules</title>
+!Pnet/mac80211/sta_info.c STA information lifetime rules
+ </sect1>
+ </chapter>
+
+ <chapter id="synchronisation">
+ <title>Synchronisation</title>
+ <para>TBD</para>
+ <para>Locking, lots of RCU</para>
+ </chapter>
+ </part>
+</book>
---------------------------
-What: bcm43xx wireless network driver
-When: 2.6.26
-Files: drivers/net/wireless/bcm43xx
-Why: This driver's functionality has been replaced by the
- mac80211-based b43 and b43legacy drivers.
-Who: John W. Linville <linville@tuxdriver.com>
-
----------------------------
-
-What: ieee80211 softmac wireless networking component
-When: 2.6.26 (or after removal of bcm43xx and port of zd1211rw to mac80211)
-Files: net/ieee80211/softmac
-Why: No in-kernel drivers will depend on it any longer.
-Who: John W. Linville <linville@tuxdriver.com>
-
----------------------------
-
-What: rc80211-simple rate control algorithm for mac80211
-When: 2.6.26
-Files: net/mac80211/rc80211-simple.c
-Why: This algorithm was provided for reference but always exhibited bad
- responsiveness and performance and has some serious flaws. It has been
- replaced by rc80211-pid.
-Who: Stefano Brivio <stefano.brivio@polimi.it>
-
----------------------------
-
What (Why):
- include/linux/netfilter_ipv4/ipt_TOS.h ipt_tos.h header files
(superseded by xt_TOS/xt_tos target & match)
e.g. With the BCM4318 on the Acer Aspire 5020 series:
ndiswrapper: Light blinks on when transmitting
-bcm43xx/b43: Solid light, blinks off when transmitting
+b43: Solid light, blinks off when transmitting
Wireless radio control is unconditionally enabled - all Acer laptops that support
acer-wmi come with built-in wireless. However, should you feel so inclined to
+++ /dev/null
-
- BCM43xx Linux Driver Project
- ============================
-
-Introduction
-------------
-
-Many of the wireless devices found in modern notebook computers are
-based on the wireless chips produced by Broadcom. These devices have
-been a problem for Linux users as there is no open-source driver
-available. In addition, Broadcom has not released specifications
-for the device, and driver availability has been limited to the
-binary-only form used in the GPL versions of AP hardware such as the
-Linksys WRT54G, and the Windows and OS X drivers. Before this project
-began, the only way to use these devices were to use the Windows or
-OS X drivers with either the Linuxant or ndiswrapper modules. There
-is a strong penalty if this method is used as loading the binary-only
-module "taints" the kernel, and no kernel developer will help diagnose
-any kernel problems.
-
-Development
------------
-
-This driver has been developed using
-a clean-room technique that is described at
-http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal
-reasons, none of the clean-room crew works on the on the Linux driver,
-and none of the Linux developers sees anything but the specifications,
-which are the ultimate product of the reverse-engineering group.
-
-Software
---------
-
-Since the release of the 2.6.17 kernel, the bcm43xx driver has been
-distributed with the kernel source, and is prebuilt in most, if not
-all, distributions. There is, however, additional software that is
-required. The firmware used by the chip is the intellectual property
-of Broadcom and they have not given the bcm43xx team redistribution
-rights to this firmware. Since we cannot legally redistribute
-the firmware we cannot include it with the driver. Furthermore, it
-cannot be placed in the downloadable archives of any distributing
-organization; therefore, the user is responsible for obtaining the
-firmware and placing it in the appropriate location so that the driver
-can find it when initializing.
-
-To help with this process, the bcm43xx developers provide a separate
-program named bcm43xx-fwcutter to "cut" the firmware out of a
-Windows or OS X driver and write the extracted files to the proper
-location. This program is usually provided with the distribution;
-however, it may be downloaded from
-
-http://developer.berlios.de/project/showfiles.php?group_id=4547
-
-The firmware is available in two versions. V3 firmware is used with
-the in-kernel bcm43xx driver that uses a software MAC layer called
-SoftMAC, and will have a microcode revision of 0x127 or smaller. The
-V4 firmware is used by an out-of-kernel driver employing a variation of
-the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches
-a satisfactory level of development, it will replace bcm43xx-softmac
-in the kernel as it is much more flexible and powerful.
-
-A source for the latest V3 firmware is
-
-http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o
-
-Once this file is downloaded, the command
-'bcm43xx-fwcutter -w <dir> <filename>'
-will extract the microcode and write it to directory
-<dir>. The correct directory will depend on your distribution;
-however, most use '/lib/firmware'. Once this step is completed,
-the bcm3xx driver should load when the system is booted. To see
-any messages relating to the driver, issue the command 'dmesg |
-grep bcm43xx' from a terminal window. If there are any problems,
-please send that output to Bcm43xx-dev@lists.berlios.de.
-
-Although the driver has been in-kernel since 2.6.17, the earliest
-version is quite limited in its capability. Patches that include
-all features of later versions are available for the stable kernel
-versions from 2.6.18. These will be needed if you use a BCM4318,
-or a PCI Express version (BCM4311 and BCM4312). In addition, if you
-have an early BCM4306 and more than 1 GB RAM, your kernel will need
-to be patched. These patches, which are being updated regularly,
-are available at ftp://lwfinger.dynalias.org/patches. Look for
-combined_2.6.YY.patch. Of course you will need kernel source downloaded
-from kernel.org, or the source from your distribution.
-
-If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG
-and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is
-essential for solving any problems.
W: http://linuxwireless.org/en/users/Drivers/b43
S: Maintained
-BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION)
-P: Larry Finger
-M: Larry.Finger@lwfinger.net
-P: Stefano Brivio
-M: stefano.brivio@polimi.it
-L: linux-wireless@vger.kernel.org
-W: http://bcm43xx.berlios.de/
-S: Obsolete
-
BEFS FILE SYSTEM
P: Sergey S. Kostyliov
M: rathamahata@php4.ru
L: lm-sensors@lm-sensors.org
S: Maintained
-SOFTMAC LAYER (IEEE 802.11)
-P: Daniel Drake
-M: dsd@gentoo.org
-L: linux-wireless@vger.kernel.org
-S: Obsolete
-
SOFTWARE RAID (Multiple Disks) SUPPORT
P: Ingo Molnar
M: mingo@redhat.com
if (!slave || !slave_do_arp_validate(bond, slave))
goto out_unlock;
- /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
- if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
- (2 * dev->addr_len) +
- (2 * sizeof(u32)))))
+ if (!pskb_may_pull(skb, arp_hdr_len(dev)))
goto out_unlock;
arp = arp_hdr(skb);
struct bonding *bond, *bond_next;
struct vlan_entry *vlan, *vlan_next;
+ if (ifa->ifa_dev->dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) {
if (bond->dev == event_dev) {
switch (event) {
} else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE))
setup_l2e_send_pending(dev, NULL, e);
} else {
- e->state = neigh_is_connected(neigh) ?
+ e->state = neigh->nud_state & NUD_CONNECTED ?
L2T_STATE_VALID : L2T_STATE_STALE;
if (memcmp(e->dmac, neigh->ha, 6))
setup_l2e_send_pending(dev, NULL, e);
#define niu_unlock_parent(np, flags) \
spin_unlock_irqrestore(&np->parent->lock, flags)
+static int serdes_init_10g_serdes(struct niu *np);
+
static int __niu_wait_bits_clear_mac(struct niu *np, unsigned long reg,
u64 bits, int limit, int delay)
{
return 0;
}
+static int serdes_init_1g_serdes(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i;
+ u64 ctrl_val, test_cfg_val, sig, mask, val;
+ int err;
+ u64 reset_val, val_rd;
+
+ val = ENET_SERDES_PLL_HRATE0 | ENET_SERDES_PLL_HRATE1 |
+ ENET_SERDES_PLL_HRATE2 | ENET_SERDES_PLL_HRATE3 |
+ ENET_SERDES_PLL_FBDIV0;
+ switch (np->port) {
+ case 0:
+ reset_val = ENET_SERDES_RESET_0;
+ ctrl_reg = ENET_SERDES_0_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_0_TEST_CFG;
+ pll_cfg = ENET_SERDES_0_PLL_CFG;
+ break;
+ case 1:
+ reset_val = ENET_SERDES_RESET_1;
+ ctrl_reg = ENET_SERDES_1_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_1_TEST_CFG;
+ pll_cfg = ENET_SERDES_1_PLL_CFG;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
+ ENET_SERDES_CTRL_SDET_1 |
+ ENET_SERDES_CTRL_SDET_2 |
+ ENET_SERDES_CTRL_SDET_3 |
+ (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
+ test_cfg_val = 0;
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_0_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_1_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_2_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_3_SHIFT));
+ }
+
+ nw64(ENET_SERDES_RESET, reset_val);
+ mdelay(20);
+ val_rd = nr64(ENET_SERDES_RESET);
+ val_rd &= ~reset_val;
+ nw64(pll_cfg, val);
+ nw64(ctrl_reg, ctrl_val);
+ nw64(test_cfg_reg, test_cfg_val);
+ nw64(ENET_SERDES_RESET, val_rd);
+ mdelay(2000);
+
+ /* Initialize all 4 lanes of the SERDES. */
+ for (i = 0; i < 4; i++) {
+ u32 rxtx_ctrl, glue0;
+
+ err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_read_glue0(np, i, &glue0);
+ if (err)
+ return err;
+
+ rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
+ rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
+ (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
+
+ glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
+ ESR_GLUE_CTRL0_THCNT |
+ ESR_GLUE_CTRL0_BLTIME);
+ glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
+ (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
+ (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
+ (BLTIME_300_CYCLES <<
+ ESR_GLUE_CTRL0_BLTIME_SHIFT));
+
+ err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_write_glue0(np, i, glue0);
+ if (err)
+ return err;
+ }
+
+
+ sig = nr64(ESR_INT_SIGNALS);
+ switch (np->port) {
+ case 0:
+ val = (ESR_INT_SRDY0_P0 | ESR_INT_DET0_P0);
+ mask = val;
+ break;
+
+ case 1:
+ val = (ESR_INT_SRDY0_P1 | ESR_INT_DET0_P1);
+ mask = val;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((sig & mask) != val) {
+ dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
+ "[%08x]\n", np->port, (int) (sig & mask), (int) val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int link_status_1g_serdes(struct niu *np, int *link_up_p)
+{
+ struct niu_link_config *lp = &np->link_config;
+ int link_up;
+ u64 val;
+ u16 current_speed;
+ unsigned long flags;
+ u8 current_duplex;
+
+ link_up = 0;
+ current_speed = SPEED_INVALID;
+ current_duplex = DUPLEX_INVALID;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ val = nr64_pcs(PCS_MII_STAT);
+
+ if (val & PCS_MII_STAT_LINK_STATUS) {
+ link_up = 1;
+ current_speed = SPEED_1000;
+ current_duplex = DUPLEX_FULL;
+ }
+
+ lp->active_speed = current_speed;
+ lp->active_duplex = current_duplex;
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ *link_up_p = link_up;
+ return 0;
+}
+
+
+static int link_status_10g_serdes(struct niu *np, int *link_up_p)
+{
+ unsigned long flags;
+ struct niu_link_config *lp = &np->link_config;
+ int link_up = 0;
+ int link_ok = 1;
+ u64 val, val2;
+ u16 current_speed;
+ u8 current_duplex;
+
+ if (!(np->flags & NIU_FLAGS_10G))
+ return link_status_1g_serdes(np, link_up_p);
+
+ current_speed = SPEED_INVALID;
+ current_duplex = DUPLEX_INVALID;
+ spin_lock_irqsave(&np->lock, flags);
+
+ val = nr64_xpcs(XPCS_STATUS(0));
+ val2 = nr64_mac(XMAC_INTER2);
+ if (val2 & 0x01000000)
+ link_ok = 0;
+
+ if ((val & 0x1000ULL) && link_ok) {
+ link_up = 1;
+ current_speed = SPEED_10000;
+ current_duplex = DUPLEX_FULL;
+ }
+ lp->active_speed = current_speed;
+ lp->active_duplex = current_duplex;
+ spin_unlock_irqrestore(&np->lock, flags);
+ *link_up_p = link_up;
+ return 0;
+}
+
+
+static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u16 current_speed, bmsr;
+ unsigned long flags;
+ u8 current_duplex;
+ int err, link_up;
+
+ link_up = 0;
+ current_speed = SPEED_INVALID;
+ current_duplex = DUPLEX_INVALID;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ err = -EINVAL;
+
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ goto out;
+
+ bmsr = err;
+ if (bmsr & BMSR_LSTATUS) {
+ u16 adv, lpa, common, estat;
+
+ err = mii_read(np, np->phy_addr, MII_ADVERTISE);
+ if (err < 0)
+ goto out;
+ adv = err;
+
+ err = mii_read(np, np->phy_addr, MII_LPA);
+ if (err < 0)
+ goto out;
+ lpa = err;
+
+ common = adv & lpa;
+
+ err = mii_read(np, np->phy_addr, MII_ESTATUS);
+ if (err < 0)
+ goto out;
+ estat = err;
+ link_up = 1;
+ current_speed = SPEED_1000;
+ current_duplex = DUPLEX_FULL;
+
+ }
+ lp->active_speed = current_speed;
+ lp->active_duplex = current_duplex;
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ *link_up_p = link_up;
+ return err;
+}
+
+
static int bcm8704_reset(struct niu *np)
{
int err, limit;
return 0;
}
+
+
+static int xcvr_init_1g_rgmii(struct niu *np)
+{
+ int err;
+ u64 val;
+ u16 bmcr, bmsr, estat;
+
+ val = nr64(MIF_CONFIG);
+ val &= ~MIF_CONFIG_INDIRECT_MODE;
+ nw64(MIF_CONFIG, val);
+
+ err = mii_reset(np);
+ if (err)
+ return err;
+
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ return err;
+ bmsr = err;
+
+ estat = 0;
+ if (bmsr & BMSR_ESTATEN) {
+ err = mii_read(np, np->phy_addr, MII_ESTATUS);
+ if (err < 0)
+ return err;
+ estat = err;
+ }
+
+ bmcr = 0;
+ err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
+ if (err)
+ return err;
+
+ if (bmsr & BMSR_ESTATEN) {
+ u16 ctrl1000 = 0;
+
+ if (estat & ESTATUS_1000_TFULL)
+ ctrl1000 |= ADVERTISE_1000FULL;
+ err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000);
+ if (err)
+ return err;
+ }
+
+ bmcr = (BMCR_SPEED1000 | BMCR_FULLDPLX);
+
+ err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
+ if (err)
+ return err;
+
+ err = mii_read(np, np->phy_addr, MII_BMCR);
+ if (err < 0)
+ return err;
+ bmcr = mii_read(np, np->phy_addr, MII_BMCR);
+
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+
static int mii_init_common(struct niu *np)
{
struct niu_link_config *lp = &np->link_config;
add_timer(&np->timer);
}
+static const struct niu_phy_ops phy_ops_10g_serdes = {
+ .serdes_init = serdes_init_10g_serdes,
+ .link_status = link_status_10g_serdes,
+};
+
+static const struct niu_phy_ops phy_ops_1g_rgmii = {
+ .xcvr_init = xcvr_init_1g_rgmii,
+ .link_status = link_status_1g_rgmii,
+};
+
static const struct niu_phy_ops phy_ops_10g_fiber_niu = {
.serdes_init = serdes_init_niu,
.xcvr_init = xcvr_init_10g,
.phy_addr_base = 0,
};
+static const struct niu_phy_template phy_template_1g_rgmii = {
+ .ops = &phy_ops_1g_rgmii,
+ .phy_addr_base = 0,
+};
+
+static const struct niu_phy_template phy_template_10g_serdes = {
+ .ops = &phy_ops_10g_serdes,
+ .phy_addr_base = 0,
+};
+
+static int niu_atca_port_num[4] = {
+ 0, 0, 11, 10
+};
+
+static int serdes_init_10g_serdes(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i;
+ u64 ctrl_val, test_cfg_val, sig, mask, val;
+ int err;
+ u64 reset_val;
+
+ switch (np->port) {
+ case 0:
+ reset_val = ENET_SERDES_RESET_0;
+ ctrl_reg = ENET_SERDES_0_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_0_TEST_CFG;
+ pll_cfg = ENET_SERDES_0_PLL_CFG;
+ break;
+ case 1:
+ reset_val = ENET_SERDES_RESET_1;
+ ctrl_reg = ENET_SERDES_1_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_1_TEST_CFG;
+ pll_cfg = ENET_SERDES_1_PLL_CFG;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
+ ENET_SERDES_CTRL_SDET_1 |
+ ENET_SERDES_CTRL_SDET_2 |
+ ENET_SERDES_CTRL_SDET_3 |
+ (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
+ test_cfg_val = 0;
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_0_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_1_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_2_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_3_SHIFT));
+ }
+
+ esr_reset(np);
+ nw64(pll_cfg, ENET_SERDES_PLL_FBDIV2);
+ nw64(ctrl_reg, ctrl_val);
+ nw64(test_cfg_reg, test_cfg_val);
+
+ /* Initialize all 4 lanes of the SERDES. */
+ for (i = 0; i < 4; i++) {
+ u32 rxtx_ctrl, glue0;
+
+ err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_read_glue0(np, i, &glue0);
+ if (err)
+ return err;
+
+ rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
+ rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
+ (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
+
+ glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
+ ESR_GLUE_CTRL0_THCNT |
+ ESR_GLUE_CTRL0_BLTIME);
+ glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
+ (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
+ (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
+ (BLTIME_300_CYCLES <<
+ ESR_GLUE_CTRL0_BLTIME_SHIFT));
+
+ err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_write_glue0(np, i, glue0);
+ if (err)
+ return err;
+ }
+
+
+ sig = nr64(ESR_INT_SIGNALS);
+ switch (np->port) {
+ case 0:
+ mask = ESR_INT_SIGNALS_P0_BITS;
+ val = (ESR_INT_SRDY0_P0 |
+ ESR_INT_DET0_P0 |
+ ESR_INT_XSRDY_P0 |
+ ESR_INT_XDP_P0_CH3 |
+ ESR_INT_XDP_P0_CH2 |
+ ESR_INT_XDP_P0_CH1 |
+ ESR_INT_XDP_P0_CH0);
+ break;
+
+ case 1:
+ mask = ESR_INT_SIGNALS_P1_BITS;
+ val = (ESR_INT_SRDY0_P1 |
+ ESR_INT_DET0_P1 |
+ ESR_INT_XSRDY_P1 |
+ ESR_INT_XDP_P1_CH3 |
+ ESR_INT_XDP_P1_CH2 |
+ ESR_INT_XDP_P1_CH1 |
+ ESR_INT_XDP_P1_CH0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((sig & mask) != val) {
+ int err;
+ err = serdes_init_1g_serdes(np);
+ if (!err) {
+ np->flags &= ~NIU_FLAGS_10G;
+ np->mac_xcvr = MAC_XCVR_PCS;
+ } else {
+ dev_err(np->device, PFX "Port %u 10G/1G SERDES Link Failed \n",
+ np->port);
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
static int niu_determine_phy_disposition(struct niu *np)
{
struct niu_parent *parent = np->parent;
tp = &phy_template_niu;
phy_addr_off += np->port;
} else {
- switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {
+ switch (np->flags &
+ (NIU_FLAGS_10G |
+ NIU_FLAGS_FIBER |
+ NIU_FLAGS_XCVR_SERDES)) {
case 0:
/* 1G copper */
tp = &phy_template_1g_copper;
phy_addr_off += np->port;
break;
+ case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES:
+ case NIU_FLAGS_XCVR_SERDES | NIU_FLAGS_FIBER:
+ case NIU_FLAGS_XCVR_SERDES:
+ switch(np->port) {
+ case 0:
+ case 1:
+ tp = &phy_template_10g_serdes;
+ break;
+ case 2:
+ case 3:
+ tp = &phy_template_1g_rgmii;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ phy_addr_off = niu_atca_port_num[np->port];
+ break;
+
default:
return -EINVAL;
}
struct niu_link_config *lp = &np->link_config;
u64 val;
+ if (np->flags & NIU_FLAGS_XCVR_SERDES) {
+ val = nr64(MIF_CONFIG);
+ val |= MIF_CONFIG_ATCA_GE;
+ nw64(MIF_CONFIG, val);
+ }
+
val = nr64_mac(XMAC_CONFIG);
val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
val &= ~XMAC_CONFIG_LFS_DISABLE;
} else {
val |= XMAC_CONFIG_LFS_DISABLE;
- if (!(np->flags & NIU_FLAGS_FIBER))
+ if (!(np->flags & NIU_FLAGS_FIBER) &&
+ !(np->flags & NIU_FLAGS_XCVR_SERDES))
val |= XMAC_CONFIG_1G_PCS_BYPASS;
else
val &= ~XMAC_CONFIG_1G_PCS_BYPASS;
static void niu_pcs_mii_reset(struct niu *np)
{
+ int limit = 1000;
u64 val = nr64_pcs(PCS_MII_CTL);
val |= PCS_MII_CTL_RST;
nw64_pcs(PCS_MII_CTL, val);
+ while ((--limit >= 0) && (val & PCS_MII_CTL_RST)) {
+ udelay(100);
+ val = nr64_pcs(PCS_MII_CTL);
+ }
}
static void niu_xpcs_reset(struct niu *np)
{
+ int limit = 1000;
u64 val = nr64_xpcs(XPCS_CONTROL1);
val |= XPCS_CONTROL1_RESET;
nw64_xpcs(XPCS_CONTROL1, val);
+ while ((--limit >= 0) && (val & XPCS_CONTROL1_RESET)) {
+ udelay(100);
+ val = nr64_xpcs(XPCS_CONTROL1);
+ }
}
static int niu_init_pcs(struct niu *np)
struct niu_link_config *lp = &np->link_config;
u64 val;
- switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {
+ switch (np->flags & (NIU_FLAGS_10G |
+ NIU_FLAGS_FIBER |
+ NIU_FLAGS_XCVR_SERDES)) {
case NIU_FLAGS_FIBER:
/* 1G fiber */
nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE);
case NIU_FLAGS_10G:
case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
+ case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES:
+ /* 10G SERDES */
if (!(np->flags & NIU_FLAGS_XMAC))
return -EINVAL;
(void) nr64_xpcs(XPCS_SYMERR_CNT23);
break;
+
+ case NIU_FLAGS_XCVR_SERDES:
+ /* 1G SERDES */
+ niu_pcs_mii_reset(np);
+ nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE);
+ nw64_pcs(PCS_DPATH_MODE, 0);
+ break;
+
case 0:
/* 1G copper */
+ case NIU_FLAGS_XCVR_SERDES | NIU_FLAGS_FIBER:
+ /* 1G RGMII FIBER */
nw64_pcs(PCS_DPATH_MODE, PCS_DPATH_MODE_MII);
niu_pcs_mii_reset(np);
break;
return;
}
- if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
+ if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
+ !strcmp(np->vpd.model, "SUNW,CP3260")) {
+ np->flags |= NIU_FLAGS_10G;
+ np->flags &= ~NIU_FLAGS_FIBER;
+ np->flags |= NIU_FLAGS_XCVR_SERDES;
+ np->mac_xcvr = MAC_XCVR_PCS;
+ if (np->port > 1) {
+ np->flags |= NIU_FLAGS_FIBER;
+ np->flags &= ~NIU_FLAGS_10G;
+ }
+ if (np->flags & NIU_FLAGS_10G)
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ } else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
dev_err(np->device, PFX "Illegal phy string [%s].\n",
np->vpd.phy_type);
dev_err(np->device, PFX "Falling back to SPROM.\n");
u32 val;
int err;
- err = fill_phy_probe_info(np, parent, info);
- if (err)
- return err;
- num_10g = count_10g_ports(info, &lowest_10g);
- num_1g = count_1g_ports(info, &lowest_1g);
-
- switch ((num_10g << 4) | num_1g) {
- case 0x24:
- if (lowest_1g == 10)
- parent->plat_type = PLAT_TYPE_VF_P0;
- else if (lowest_1g == 26)
- parent->plat_type = PLAT_TYPE_VF_P1;
- else
- goto unknown_vg_1g_port;
-
- /* fallthru */
- case 0x22:
- val = (phy_encode(PORT_TYPE_10G, 0) |
- phy_encode(PORT_TYPE_10G, 1) |
+ if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
+ !strcmp(np->vpd.model, "SUNW,CP3260")) {
+ num_10g = 0;
+ num_1g = 2;
+ parent->plat_type = PLAT_TYPE_ATCA_CP3220;
+ parent->num_ports = 4;
+ val = (phy_encode(PORT_TYPE_1G, 0) |
+ phy_encode(PORT_TYPE_1G, 1) |
phy_encode(PORT_TYPE_1G, 2) |
phy_encode(PORT_TYPE_1G, 3));
- break;
-
- case 0x20:
- val = (phy_encode(PORT_TYPE_10G, 0) |
- phy_encode(PORT_TYPE_10G, 1));
- break;
+ } else {
+ err = fill_phy_probe_info(np, parent, info);
+ if (err)
+ return err;
- case 0x10:
- val = phy_encode(PORT_TYPE_10G, np->port);
- break;
+ num_10g = count_10g_ports(info, &lowest_10g);
+ num_1g = count_1g_ports(info, &lowest_1g);
- case 0x14:
- if (lowest_1g == 10)
- parent->plat_type = PLAT_TYPE_VF_P0;
- else if (lowest_1g == 26)
- parent->plat_type = PLAT_TYPE_VF_P1;
- else
- goto unknown_vg_1g_port;
+ switch ((num_10g << 4) | num_1g) {
+ case 0x24:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
- /* fallthru */
- case 0x13:
- if ((lowest_10g & 0x7) == 0)
+ /* fallthru */
+ case 0x22:
val = (phy_encode(PORT_TYPE_10G, 0) |
- phy_encode(PORT_TYPE_1G, 1) |
- phy_encode(PORT_TYPE_1G, 2) |
- phy_encode(PORT_TYPE_1G, 3));
- else
- val = (phy_encode(PORT_TYPE_1G, 0) |
phy_encode(PORT_TYPE_10G, 1) |
phy_encode(PORT_TYPE_1G, 2) |
phy_encode(PORT_TYPE_1G, 3));
- break;
+ break;
- case 0x04:
- if (lowest_1g == 10)
- parent->plat_type = PLAT_TYPE_VF_P0;
- else if (lowest_1g == 26)
- parent->plat_type = PLAT_TYPE_VF_P1;
- else
- goto unknown_vg_1g_port;
+ case 0x20:
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_10G, 1));
+ break;
- val = (phy_encode(PORT_TYPE_1G, 0) |
- phy_encode(PORT_TYPE_1G, 1) |
- phy_encode(PORT_TYPE_1G, 2) |
- phy_encode(PORT_TYPE_1G, 3));
- break;
+ case 0x10:
+ val = phy_encode(PORT_TYPE_10G, np->port);
+ break;
- default:
- printk(KERN_ERR PFX "Unsupported port config "
- "10G[%d] 1G[%d]\n",
- num_10g, num_1g);
- return -EINVAL;
+ case 0x14:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
+
+ /* fallthru */
+ case 0x13:
+ if ((lowest_10g & 0x7) == 0)
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_1G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ else
+ val = (phy_encode(PORT_TYPE_1G, 0) |
+ phy_encode(PORT_TYPE_10G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ break;
+
+ case 0x04:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
+
+ val = (phy_encode(PORT_TYPE_1G, 0) |
+ phy_encode(PORT_TYPE_1G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ break;
+
+ default:
+ printk(KERN_ERR PFX "Unsupported port config "
+ "10G[%d] 1G[%d]\n",
+ num_10g, num_1g);
+ return -EINVAL;
+ }
}
parent->port_phy = val;
pr_info("%s: NIU Ethernet %s\n",
dev->name, print_mac(mac, dev->dev_addr));
- pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
- dev->name,
- (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
- (np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
- (np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"),
- (np->mac_xcvr == MAC_XCVR_MII ? "MII" :
- (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
- np->vpd.phy_type);
+ if (np->parent->plat_type == PLAT_TYPE_ATCA_CP3220) {
+ pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
+ dev->name,
+ (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
+ (np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
+ (np->flags & NIU_FLAGS_FIBER ? "RGMII FIBER" : "SERDES"),
+ (np->mac_xcvr == MAC_XCVR_MII ? "MII" :
+ (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
+ np->vpd.phy_type);
+ } else {
+ pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
+ dev->name,
+ (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
+ (np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
+ (np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"),
+ (np->mac_xcvr == MAC_XCVR_MII ? "MII" :
+ (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
+ np->vpd.phy_type);
+ }
}
static int __devinit niu_pci_init_one(struct pci_dev *pdev,
#define PLAT_TYPE_NIU 0x02
#define PLAT_TYPE_VF_P0 0x03
#define PLAT_TYPE_VF_P1 0x04
+#define PLAT_TYPE_ATCA_CP3220 0x08
u8 num_ports;
struct niu_parent *parent;
u32 flags;
+#define NIU_FLAGS_VPD_VALID 0x00800000 /* VPD has valid version */
#define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */
#define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */
#define NIU_FLAGS_PROMISC 0x00100000 /* PROMISC enabled */
-#define NIU_FLAGS_VPD_VALID 0x00080000 /* VPD has valid version */
+#define NIU_FLAGS_XCVR_SERDES 0x00080000 /* 0=PHY 1=SERDES */
#define NIU_FLAGS_10G 0x00040000 /* 0=1G 1=10G */
#define NIU_FLAGS_FIBER 0x00020000 /* 0=COPPER 1=FIBER */
#define NIU_FLAGS_XMAC 0x00010000 /* 0=BMAC 1=XMAC */
static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
{
struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+ struct net_device *dev = ifa->ifa_dev->dev;
+ struct velocity_info *vptr;
+ unsigned long flags;
- if (ifa) {
- struct net_device *dev = ifa->ifa_dev->dev;
- struct velocity_info *vptr;
- unsigned long flags;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
- spin_lock_irqsave(&velocity_dev_list_lock, flags);
- list_for_each_entry(vptr, &velocity_dev_list, list) {
- if (vptr->dev == dev) {
- velocity_get_ip(vptr);
- break;
- }
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_for_each_entry(vptr, &velocity_dev_list, list) {
+ if (vptr->dev == dev) {
+ velocity_get_ip(vptr);
+ break;
}
- spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
}
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
+
return NOTIFY_DONE;
}
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/device.h>
#undef COSA_SLOW_IO /* for testing purposes only */
int (*tx_done)(struct channel_data *channel, int size);
/* Character device parts */
- struct semaphore rsem, wsem;
+ struct mutex rlock;
+ struct semaphore wsem;
char *rxdata;
int rxsize;
wait_queue_head_t txwaitq, rxwaitq;
static void chardev_channel_init(struct channel_data *chan)
{
- init_MUTEX(&chan->rsem);
+ mutex_init(&chan->rlock);
init_MUTEX(&chan->wsem);
}
cosa->name, cosa->firmware_status);
return -EPERM;
}
- if (down_interruptible(&chan->rsem))
+ if (mutex_lock_interruptible(&chan->rlock))
return -ERESTARTSYS;
if ((chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL)) == NULL) {
printk(KERN_INFO "%s: cosa_read() - OOM\n", cosa->name);
- up(&chan->rsem);
+ mutex_unlock(&chan->rlock);
return -ENOMEM;
}
remove_wait_queue(&chan->rxwaitq, &wait);
current->state = TASK_RUNNING;
spin_unlock_irqrestore(&cosa->lock, flags);
- up(&chan->rsem);
+ mutex_unlock(&chan->rlock);
return -ERESTARTSYS;
}
}
kbuf = chan->rxdata;
count = chan->rxsize;
spin_unlock_irqrestore(&cosa->lock, flags);
- up(&chan->rsem);
+ mutex_unlock(&chan->rlock);
if (copy_to_user(buf, kbuf, count)) {
kfree(kbuf);
configure your card:
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+ It is recommended that you compile this driver as a module (M)
+ rather than built-in (Y). This driver requires firmware at device
+ initialization time, and when built-in this typically happens
+ before the filesystem is accessible (hence firmware will be
+ unavailable and initialization will fail). If you do choose to build
+ this driver into your kernel image, you can avoid this problem by
+ including the firmware and a firmware loader in an initramfs.
- If you want to compile the driver as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt>.
- The module will be called ipw2100.ko.
-
config IPW2100_MONITOR
bool "Enable promiscuous mode"
depends on IPW2100
configure your card:
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- If you want to compile the driver as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt>.
- The module will be called ipw2200.ko.
+
+ It is recommended that you compile this driver as a module (M)
+ rather than built-in (Y). This driver requires firmware at device
+ initialization time, and when built-in this typically happens
+ before the filesystem is accessible (hence firmware will be
+ unavailable and initialization will fail). If you do choose to build
+ this driver into your kernel image, you can avoid this problem by
+ including the firmware and a firmware loader in an initramfs.
config IPW2200_MONITOR
bool "Enable promiscuous mode"
If you choose to build a module, it'll be called p54pci.
-config ATH5K
- tristate "Atheros 5xxx wireless cards support"
- depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
- ---help---
- This module adds support for wireless adapters based on
- Atheros 5xxx chipset.
-
- Currently the following chip versions are supported:
-
- MAC: AR5211 AR5212
- PHY: RF5111/2111 RF5112/2112 RF5413/2413
-
- This driver uses the kernel's mac80211 subsystem.
-
- If you choose to build a module, it'll be called ath5k. Say M if
- unsure.
-
+source "drivers/net/wireless/ath5k/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
-source "drivers/net/wireless/bcm43xx/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/b43legacy/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
obj-$(CONFIG_PRISM54) += prism54/
obj-$(CONFIG_HOSTAP) += hostap/
-obj-$(CONFIG_BCM43XX) += bcm43xx/
obj-$(CONFIG_B43) += b43/
obj-$(CONFIG_B43LEGACY) += b43legacy/
obj-$(CONFIG_ZD1211RW) += zd1211rw/
{ 0 }
};
+static struct ieee80211_rate adm8211_rates[] = {
+ { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 220, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, /* XX ?? */
+};
+
+static const struct ieee80211_channel adm8211_channels[] = {
+ { .center_freq = 2412},
+ { .center_freq = 2417},
+ { .center_freq = 2422},
+ { .center_freq = 2427},
+ { .center_freq = 2432},
+ { .center_freq = 2437},
+ { .center_freq = 2442},
+ { .center_freq = 2447},
+ { .center_freq = 2452},
+ { .center_freq = 2457},
+ { .center_freq = 2462},
+ { .center_freq = 2467},
+ { .center_freq = 2472},
+ { .center_freq = 2484},
+};
+
+
static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom)
{
struct adm8211_priv *priv = eeprom->data;
printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n",
pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max);
- priv->modes[0].num_channels = chan_range.max - chan_range.min + 1;
- priv->modes[0].channels = priv->channels;
+ BUILD_BUG_ON(sizeof(priv->channels) != sizeof(adm8211_channels));
- memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels));
+ memcpy(priv->channels, adm8211_channels, sizeof(priv->channels));
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = ARRAY_SIZE(adm8211_channels);
+ priv->band.bitrates = adm8211_rates;
+ priv->band.n_bitrates = ARRAY_SIZE(adm8211_rates);
for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++)
- if (i >= chan_range.min && i <= chan_range.max)
- priv->channels[i - 1].flag =
- IEEE80211_CHAN_W_SCAN |
- IEEE80211_CHAN_W_ACTIVE_SCAN |
- IEEE80211_CHAN_W_IBSS;
+ if (i < chan_range.min || i > chan_range.max)
+ priv->channels[i - 1].flags |= IEEE80211_CHAN_DISABLED;
switch (priv->eeprom->specific_bbptype) {
case ADM8211_BBP_RFMD3000:
unsigned int pktlen;
struct sk_buff *skb, *newskb;
unsigned int limit = priv->rx_ring_size;
- static const u8 rate_tbl[] = {10, 20, 55, 110, 220};
u8 rssi, rate;
while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) {
else
rx_status.ssi = 100 - rssi;
- if (rate <= 4)
- rx_status.rate = rate_tbl[rate];
+ rx_status.rate_idx = rate;
- rx_status.channel = priv->channel;
- rx_status.freq = adm8211_channels[priv->channel - 1].freq;
- rx_status.phymode = MODE_IEEE80211B;
+ rx_status.freq = adm8211_channels[priv->channel - 1].center_freq;
+ rx_status.band = IEEE80211_BAND_2GHZ;
ieee80211_rx_irqsafe(dev, skb, &rx_status);
}
if (priv->pdev->revision != ADM8211_REV_BA) {
rate_buf[0] = ARRAY_SIZE(adm8211_rates);
for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++)
- rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80;
+ rate_buf[i + 1] = (adm8211_rates[i].bitrate / 5) | 0x80;
} else {
/* workaround for rev BA specific bug */
rate_buf[0] = 0x04;
u32 reg;
u8 cline;
- reg = le32_to_cpu(ADM8211_CSR_READ(PAR));
+ reg = ADM8211_CSR_READ(PAR);
reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME;
reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL);
static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
{
struct adm8211_priv *priv = dev->priv;
+ int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
- if (conf->channel != priv->channel) {
- priv->channel = conf->channel;
+ if (channel != priv->channel) {
+ priv->channel = channel;
adm8211_rf_set_channel(dev, priv->channel);
}
int plcp, dur, len, plcp_signal, short_preamble;
struct ieee80211_hdr *hdr;
- if (control->tx_rate < 0) {
- short_preamble = 1;
- plcp_signal = -control->tx_rate;
- } else {
- short_preamble = 0;
- plcp_signal = control->tx_rate;
- }
+ short_preamble = !!(control->tx_rate->flags &
+ IEEE80211_TXCTL_SHORT_PREAMBLE);
+ plcp_signal = control->tx_rate->bitrate;
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
SET_IEEE80211_PERM_ADDR(dev, perm_addr);
dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
- dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
- /* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
+ /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
dev->channel_change_time = 1000;
dev->max_rssi = 100; /* FIXME: find better value */
- priv->modes[0].mode = MODE_IEEE80211B;
- /* channel info filled in by adm8211_read_eeprom */
- memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates));
- priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates);
- priv->modes[0].rates = priv->rates;
-
dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
priv->retry_limit = 3;
goto err_free_desc;
}
- priv->channel = priv->modes[0].channels[0].chan;
+ priv->channel = 1;
- err = ieee80211_register_hwmode(dev, &priv->modes[0]);
- if (err) {
- printk(KERN_ERR "%s (adm8211): Can't register hwmode\n",
- pci_name(pdev));
- goto err_free_desc;
- }
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
err = ieee80211_register_hw(dev);
if (err) {
u8 cis_data[0]; /* 0x80, 384 bytes */
} __attribute__ ((packed));
-static const struct ieee80211_rate adm8211_rates[] = {
- { .rate = 10,
- .val = 10,
- .val2 = -10,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 20,
- .val = 20,
- .val2 = -20,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 55,
- .val = 55,
- .val2 = -55,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 110,
- .val = 110,
- .val2 = -110,
- .flags = IEEE80211_RATE_CCK_2 }
-};
-
-struct ieee80211_chan_range {
- u8 min;
- u8 max;
-};
-
-static const struct ieee80211_channel adm8211_channels[] = {
- { .chan = 1,
- .freq = 2412},
- { .chan = 2,
- .freq = 2417},
- { .chan = 3,
- .freq = 2422},
- { .chan = 4,
- .freq = 2427},
- { .chan = 5,
- .freq = 2432},
- { .chan = 6,
- .freq = 2437},
- { .chan = 7,
- .freq = 2442},
- { .chan = 8,
- .freq = 2447},
- { .chan = 9,
- .freq = 2452},
- { .chan = 10,
- .freq = 2457},
- { .chan = 11,
- .freq = 2462},
- { .chan = 12,
- .freq = 2467},
- { .chan = 13,
- .freq = 2472},
- { .chan = 14,
- .freq = 2484},
-};
-
struct adm8211_priv {
struct pci_dev *pdev;
spinlock_t lock;
unsigned int cur_tx, dirty_tx, cur_rx;
struct ieee80211_low_level_stats stats;
- struct ieee80211_hw_mode modes[1];
- struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)];
- struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)];
+ struct ieee80211_supported_band band;
+ struct ieee80211_channel channels[14];
int mode;
int channel;
} transceiver_type;
};
+struct ieee80211_chan_range {
+ u8 min;
+ u8 max;
+};
+
static const struct ieee80211_chan_range cranges[] = {
{1, 11}, /* FCC */
{1, 11}, /* IC */
--- /dev/null
+config ATH5K
+ tristate "Atheros 5xxx wireless cards support"
+ depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+ ---help---
+ This module adds support for wireless adapters based on
+ Atheros 5xxx chipset.
+
+ Currently the following chip versions are supported:
+
+ MAC: AR5211 AR5212
+ PHY: RF5111/2111 RF5112/2112 RF5413/2413
+
+ This driver uses the kernel's mac80211 subsystem.
+
+ If you choose to build a module, it'll be called ath5k. Say M if
+ unsure.
+
+config ATH5K_DEBUG
+ bool "Atheros 5xxx debugging"
+ depends on ATH5K
+ ---help---
+ Atheros 5xxx debugging messages.
+
+ Say Y, if and you will get debug options for ath5k.
+ To use this, you need to mount debugfs:
+
+ mkdir /debug/
+ mount -t debugfs debug /debug/
+
+ You will get access to files under:
+ /debug/ath5k/phy0/
+
+ To enable debug, pass the debug level to the debug module
+ parameter. For example:
+
+ modprobe ath5k debug=0x00000400
+
-ath5k-objs = base.o hw.o regdom.o initvals.o phy.o debug.o
-obj-$(CONFIG_ATH5K) += ath5k.o
+ath5k-y += base.o
+ath5k-y += hw.o
+ath5k-y += initvals.o
+ath5k-y += phy.o
+ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
+obj-$(CONFIG_ATH5K) += ath5k.o
#include <net/mac80211.h>
#include "hw.h"
-#include "regdom.h"
/* PCI IDs */
#define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */
AR5K_RF5110 = 0,
AR5K_RF5111 = 1,
AR5K_RF5112 = 2,
- AR5K_RF5413 = 3,
+ AR5K_RF2413 = 3,
+ AR5K_RF5413 = 4,
};
/*
#define AR5K_SREV_VER_AR5212 0x50
#define AR5K_SREV_VER_AR5213 0x55
#define AR5K_SREV_VER_AR5213A 0x59
-#define AR5K_SREV_VER_AR2424 0xa0
-#define AR5K_SREV_VER_AR5424 0xa3
+#define AR5K_SREV_VER_AR2413 0x78
+#define AR5K_SREV_VER_AR2414 0x79
+#define AR5K_SREV_VER_AR2424 0xa0 /* PCI-E */
+#define AR5K_SREV_VER_AR5424 0xa3 /* PCI-E */
#define AR5K_SREV_VER_AR5413 0xa4
#define AR5K_SREV_VER_AR5414 0xa5
-#define AR5K_SREV_VER_AR5416 0xc0 /* ? */
-#define AR5K_SREV_VER_AR5418 0xca
+#define AR5K_SREV_VER_AR5416 0xc0 /* PCI-E */
+#define AR5K_SREV_VER_AR5418 0xca /* PCI-E */
+#define AR5K_SREV_VER_AR2425 0xe2 /* PCI-E */
#define AR5K_SREV_RAD_5110 0x00
#define AR5K_SREV_RAD_5111 0x10
#define AR5K_SREV_RAD_5112A 0x35
#define AR5K_SREV_RAD_2112 0x40
#define AR5K_SREV_RAD_2112A 0x45
+#define AR5K_SREV_RAD_SC0 0x56 /* Found on 2413/2414 */
#define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */
-#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424/5424 */
+#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424-5/5424 */
#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */
/* IEEE defs */
*/
#define MODULATION_TURBO 0x00000080
-enum ath5k_vendor_mode {
- MODE_ATHEROS_TURBO = NUM_IEEE80211_MODES+1,
- MODE_ATHEROS_TURBOG
+enum ath5k_driver_mode {
+ AR5K_MODE_11A = 0,
+ AR5K_MODE_11A_TURBO = 1,
+ AR5K_MODE_11B = 2,
+ AR5K_MODE_11G = 3,
+ AR5K_MODE_11G_TURBO = 4,
+ AR5K_MODE_XR = 0,
+ AR5K_MODE_MAX = 5
};
-/* Number of supported mac80211 enum ieee80211_phymode modes by this driver */
-#define NUM_DRIVER_MODES 3
-
/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */
#define AR5K_SET_SHORT_PREAMBLE 0x04
-#define HAS_SHPREAMBLE(_ix) (rt->rates[_ix].modulation == IEEE80211_RATE_CCK_2)
-#define SHPREAMBLE_FLAG(_ix) (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0)
+#define HAS_SHPREAMBLE(_ix) \
+ (rt->rates[_ix].modulation == IEEE80211_RATE_SHORT_PREAMBLE)
+#define SHPREAMBLE_FLAG(_ix) \
+ (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0)
+
/****************\
TX DEFINITIONS
\****************/
/*
- * Tx Descriptor
+ * TX Status
*/
struct ath5k_tx_status {
u16 ts_seqnum;
\****************/
/*
- * Rx Descriptor
+ * RX Status
*/
struct ath5k_rx_status {
u16 rs_datalen;
};
-
-
/**************************\
BEACON TIMERS DEFINITIONS
\**************************/
#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
-
/********************\
COMMON DEFINITIONS
\********************/
/*
- * Atheros descriptor
+ * Atheros hardware descriptor
+ * This is read and written to by the hardware
*/
struct ath5k_desc {
- u32 ds_link;
- u32 ds_data;
- u32 ds_ctl0;
- u32 ds_ctl1;
- u32 ds_hw[4];
+ u32 ds_link; /* physical address of the next descriptor */
+ u32 ds_data; /* physical address of data buffer (skb) */
union {
- struct ath5k_rx_status rx;
- struct ath5k_tx_status tx;
- } ds_us;
-
-#define ds_rxstat ds_us.rx
-#define ds_txstat ds_us.tx
-
+ struct ath5k_hw_5210_tx_desc ds_tx5210;
+ struct ath5k_hw_5212_tx_desc ds_tx5212;
+ struct ath5k_hw_all_rx_desc ds_rx;
+ } ud;
} __packed;
#define AR5K_RXDESC_INTREQ 0x0020
* Used internaly in OpenHAL (ar5211.c/ar5212.c
* for reset_tx_queue). Also see struct struct ieee80211_channel.
*/
-#define IS_CHAN_XR(_c) ((_c.val & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c) ((_c.val & CHANNEL_B) != 0)
+#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0)
/*
* The following structure will be used to map 2GHz channels to
/**
* struct ath5k_rate - rate structure
- * @valid: is this a valid rate for the current mode
+ * @valid: is this a valid rate for rate control (remove)
* @modulation: respective mac80211 modulation
* @rate_kbps: rate in kbit/s
* @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on
/*
* Rate tables...
+ * TODO: CLEAN THIS !!!
*/
#define AR5K_RATES_11A { 8, { \
255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \
7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \
255, 255, 255, 255, 255, 255, 255, 255 }, { \
- { 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 0 }, \
- { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 0 }, \
- { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 2 }, \
- { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 2 }, \
- { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 4 }, \
- { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 4 }, \
- { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 4 }, \
- { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 4 } } \
+ { 1, 0, 6000, 11, 140, 0 }, \
+ { 1, 0, 9000, 15, 18, 0 }, \
+ { 1, 0, 12000, 10, 152, 2 }, \
+ { 1, 0, 18000, 14, 36, 2 }, \
+ { 1, 0, 24000, 9, 176, 4 }, \
+ { 1, 0, 36000, 13, 72, 4 }, \
+ { 1, 0, 48000, 8, 96, 4 }, \
+ { 1, 0, 54000, 12, 108, 4 } } \
}
#define AR5K_RATES_11B { 4, { \
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \
3, 2, 1, 0, 255, 255, 255, 255 }, { \
- { 1, IEEE80211_RATE_CCK, 1000, 27, 130, 0 }, \
- { 1, IEEE80211_RATE_CCK_2, 2000, 26, 132, 1 }, \
- { 1, IEEE80211_RATE_CCK_2, 5500, 25, 139, 1 }, \
- { 1, IEEE80211_RATE_CCK_2, 11000, 24, 150, 1 } } \
+ { 1, 0, 1000, 27, 130, 0 }, \
+ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 132, 1 }, \
+ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 139, 1 }, \
+ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 150, 1 } } \
}
#define AR5K_RATES_11G { 12, { \
255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4, \
11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \
3, 2, 1, 0, 255, 255, 255, 255 }, { \
- { 1, IEEE80211_RATE_CCK, 1000, 27, 2, 0 }, \
- { 1, IEEE80211_RATE_CCK_2, 2000, 26, 4, 1 }, \
- { 1, IEEE80211_RATE_CCK_2, 5500, 25, 11, 1 }, \
- { 1, IEEE80211_RATE_CCK_2, 11000, 24, 22, 1 }, \
- { 0, IEEE80211_RATE_OFDM, 6000, 11, 12, 4 }, \
- { 0, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 }, \
- { 1, IEEE80211_RATE_OFDM, 12000, 10, 24, 6 }, \
- { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 }, \
- { 1, IEEE80211_RATE_OFDM, 24000, 9, 48, 8 }, \
- { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 }, \
- { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 }, \
- { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \
+ { 1, 0, 1000, 27, 2, 0 }, \
+ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 4, 1 }, \
+ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 11, 1 }, \
+ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 22, 1 }, \
+ { 0, 0, 6000, 11, 12, 4 }, \
+ { 0, 0, 9000, 15, 18, 4 }, \
+ { 1, 0, 12000, 10, 24, 6 }, \
+ { 1, 0, 18000, 14, 36, 6 }, \
+ { 1, 0, 24000, 9, 48, 8 }, \
+ { 1, 0, 36000, 13, 72, 8 }, \
+ { 1, 0, 48000, 8, 96, 8 }, \
+ { 1, 0, 54000, 12, 108, 8 } } \
}
#define AR5K_RATES_TURBO { 8, { \
{ 1, MODULATION_XR, 1000, 2, 139, 1 }, \
{ 1, MODULATION_XR, 2000, 6, 150, 2 }, \
{ 1, MODULATION_XR, 3000, 1, 150, 3 }, \
- { 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 4 }, \
- { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 }, \
- { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 6 }, \
- { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 }, \
- { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 8 }, \
- { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 }, \
- { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 }, \
- { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \
+ { 1, 0, 6000, 11, 140, 4 }, \
+ { 1, 0, 9000, 15, 18, 4 }, \
+ { 1, 0, 12000, 10, 152, 6 }, \
+ { 1, 0, 18000, 14, 36, 6 }, \
+ { 1, 0, 24000, 9, 176, 8 }, \
+ { 1, 0, 36000, 13, 72, 8 }, \
+ { 1, 0, 48000, 8, 96, 8 }, \
+ { 1, 0, 54000, 12, 108, 8 } } \
}
/*
AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */
};
+
+/* XXX: we *may* move cap_range stuff to struct wiphy */
struct ath5k_capabilities {
/*
* Supported PHY modes
* (ie. CHANNEL_A, CHANNEL_B, ...)
*/
- DECLARE_BITMAP(cap_mode, NUM_DRIVER_MODES);
+ DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX);
/*
* Frequency range (without regulation restrictions)
} cap_range;
/*
- * Active regulation domain settings
- */
- struct {
- enum ath5k_regdom reg_current;
- enum ath5k_regdom reg_hw;
- } cap_regdomain;
-
- /*
* Values stored in the EEPROM (some of them...)
*/
struct ath5k_eeprom_info cap_eeprom;
u16 ah_phy_revision;
u16 ah_radio_5ghz_revision;
u16 ah_radio_2ghz_revision;
+ u32 ah_phy_spending;
enum ath5k_version ah_version;
enum ath5k_radio ah_radio;
int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *,
unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int);
- int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *);
- int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *);
+ int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+ struct ath5k_tx_status *);
+ int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+ struct ath5k_rx_status *);
};
/*
extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
-/* Regulatory Domain/Channels Setup */
-extern u16 ath5k_get_regdomain(struct ath5k_hw *ah);
/* Misc functions */
extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards.");
MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION("0.1.1 (EXPERIMENTAL)");
+MODULE_VERSION("0.5.0 (EXPERIMENTAL)");
/* Known PCI ids */
{ "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 },
{ "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 },
{ "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A },
+ { "2413", AR5K_VERSION_VER, AR5K_SREV_VER_AR2413 },
+ { "2414", AR5K_VERSION_VER, AR5K_SREV_VER_AR2414 },
{ "2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424 },
{ "5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424 },
{ "5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413 },
{ "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A },
{ "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 },
{ "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A },
+ { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC0 },
{ "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 },
{ "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 },
{ "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 },
static void ath5k_setcurmode(struct ath5k_softc *sc,
unsigned int mode);
static void ath5k_mode_setup(struct ath5k_softc *sc);
+static void ath5k_set_total_hw_rates(struct ath5k_softc *sc);
+
/* Descriptor setup */
static int ath5k_desc_alloc(struct ath5k_softc *sc,
struct pci_dev *pdev);
static void ath5k_rx_stop(struct ath5k_softc *sc);
static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc,
struct ath5k_desc *ds,
- struct sk_buff *skb);
+ struct sk_buff *skb,
+ struct ath5k_rx_status *rs);
static void ath5k_tasklet_rx(unsigned long data);
/* Tx handling */
static void ath5k_tx_processq(struct ath5k_softc *sc,
sc->ah->ah_mac_srev,
sc->ah->ah_phy_revision);
- if(!sc->ah->ah_single_chip){
+ if (!sc->ah->ah_single_chip) {
/* Single chip radio (!RF5111) */
- if(sc->ah->ah_radio_5ghz_revision && !sc->ah->ah_radio_2ghz_revision) {
+ if (sc->ah->ah_radio_5ghz_revision &&
+ !sc->ah->ah_radio_2ghz_revision) {
/* No 5GHz support -> report 2GHz radio */
- if(!test_bit(MODE_IEEE80211A, sc->ah->ah_capabilities.cap_mode)){
+ if (!test_bit(AR5K_MODE_11A,
+ sc->ah->ah_capabilities.cap_mode)) {
ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- /* No 2GHz support (5110 and some 5Ghz only cards) -> report 5Ghz radio */
- } else if(!test_bit(MODE_IEEE80211B, sc->ah->ah_capabilities.cap_mode)){
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ /* No 2GHz support (5110 and some
+ * 5Ghz only cards) -> report 5Ghz radio */
+ } else if (!test_bit(AR5K_MODE_11B,
+ sc->ah->ah_capabilities.cap_mode)) {
ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
/* Multiband radio */
} else {
ATH5K_INFO(sc, "RF%s multiband radio found"
" (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
}
}
- /* Multi chip radio (RF5111 - RF2111) -> report both 2GHz/5GHz radios */
- else if(sc->ah->ah_radio_5ghz_revision && sc->ah->ah_radio_2ghz_revision){
+ /* Multi chip radio (RF5111 - RF2111) ->
+ * report both 2GHz/5GHz radios */
+ else if (sc->ah->ah_radio_5ghz_revision &&
+ sc->ah->ah_radio_2ghz_revision){
ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_2ghz_revision),
- sc->ah->ah_radio_2ghz_revision);
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_2ghz_revision),
+ sc->ah->ah_radio_2ghz_revision);
}
}
goto err;
}
+ /* Set *_rates so we can map hw rate index */
+ ath5k_set_total_hw_rates(sc);
+
/* NB: setup here so ath5k_rate_update is happy */
- if (test_bit(MODE_IEEE80211A, ah->ah_modes))
- ath5k_setcurmode(sc, MODE_IEEE80211A);
+ if (test_bit(AR5K_MODE_11A, ah->ah_modes))
+ ath5k_setcurmode(sc, AR5K_MODE_11A);
else
- ath5k_setcurmode(sc, MODE_IEEE80211B);
+ ath5k_setcurmode(sc, AR5K_MODE_11B);
/*
* Allocate tx+rx descriptors and populate the lists.
return 0;
for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) {
- if (!rt->rates[i].valid)
- continue;
- rates->rate = rt->rates[i].rate_kbps / 100;
- rates->val = rt->rates[i].rate_code;
- rates->flags = rt->rates[i].modulation;
- rates++;
+ rates[count].bitrate = rt->rates[i].rate_kbps / 100;
+ rates[count].hw_value = rt->rates[i].rate_code;
+ rates[count].flags = rt->rates[i].modulation;
count++;
max--;
}
unsigned int mode,
unsigned int max)
{
- static const struct { unsigned int mode, mask, chan; } map[] = {
- [MODE_IEEE80211A] = { CHANNEL_OFDM, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_A },
- [MODE_ATHEROS_TURBO] = { CHANNEL_OFDM|CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_T },
- [MODE_IEEE80211B] = { CHANNEL_CCK, CHANNEL_CCK, CHANNEL_B },
- [MODE_IEEE80211G] = { CHANNEL_OFDM, CHANNEL_OFDM, CHANNEL_G },
- [MODE_ATHEROS_TURBOG] = { CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_TG },
- };
- static const struct ath5k_regchannel chans_2ghz[] =
- IEEE80211_CHANNELS_2GHZ;
- static const struct ath5k_regchannel chans_5ghz[] =
- IEEE80211_CHANNELS_5GHZ;
- const struct ath5k_regchannel *chans;
- enum ath5k_regdom dmn;
- unsigned int i, count, size, chfreq, all, f, ch;
+ unsigned int i, count, size, chfreq, freq, ch;
if (!test_bit(mode, ah->ah_modes))
return 0;
- all = ah->ah_regdomain == DMN_DEFAULT || CHAN_DEBUG == 1;
-
switch (mode) {
- case MODE_IEEE80211A:
- case MODE_ATHEROS_TURBO:
+ case AR5K_MODE_11A:
+ case AR5K_MODE_11A_TURBO:
/* 1..220, but 2GHz frequencies are filtered by check_channel */
- size = all ? 220 : ARRAY_SIZE(chans_5ghz);
- chans = chans_5ghz;
- dmn = ath5k_regdom2flag(ah->ah_regdomain,
- IEEE80211_CHANNELS_5GHZ_MIN);
+ size = 220 ;
chfreq = CHANNEL_5GHZ;
break;
- case MODE_IEEE80211B:
- case MODE_IEEE80211G:
- case MODE_ATHEROS_TURBOG:
- size = all ? 26 : ARRAY_SIZE(chans_2ghz);
- chans = chans_2ghz;
- dmn = ath5k_regdom2flag(ah->ah_regdomain,
- IEEE80211_CHANNELS_2GHZ_MIN);
+ case AR5K_MODE_11B:
+ case AR5K_MODE_11G:
+ case AR5K_MODE_11G_TURBO:
+ size = 26;
chfreq = CHANNEL_2GHZ;
break;
default:
}
for (i = 0, count = 0; i < size && max > 0; i++) {
- ch = all ? i + 1 : chans[i].chan;
- f = ath5k_ieee2mhz(ch);
- /* Check if channel is supported by the chipset */
- if (!ath5k_channel_ok(ah, f, chfreq))
- continue;
+ ch = i + 1 ;
+ freq = ath5k_ieee2mhz(ch);
- /* Match regulation domain */
- if (!all && !(IEEE80211_DMN(chans[i].domain) &
- IEEE80211_DMN(dmn)))
+ /* Check if channel is supported by the chipset */
+ if (!ath5k_channel_ok(ah, freq, chfreq))
continue;
- if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode)
- continue;
+ /* Write channel info and increment counter */
+ channels[count].center_freq = freq;
+ channels[count].band = (chfreq == CHANNEL_2GHZ) ?
+ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ switch (mode) {
+ case AR5K_MODE_11A:
+ case AR5K_MODE_11G:
+ channels[count].hw_value = chfreq | CHANNEL_OFDM;
+ break;
+ case AR5K_MODE_11A_TURBO:
+ case AR5K_MODE_11G_TURBO:
+ channels[count].hw_value = chfreq |
+ CHANNEL_OFDM | CHANNEL_TURBO;
+ break;
+ case AR5K_MODE_11B:
+ channels[count].hw_value = CHANNEL_B;
+ }
- /* Write channel and increment counter */
- channels->chan = ch;
- channels->freq = f;
- channels->val = map[mode].chan;
- channels++;
count++;
max--;
}
return count;
}
-/* Only tries to register modes our EEPROM says it can support */
-#define REGISTER_MODE(m) do { \
- ret = ath5k_register_mode(hw, m); \
- if (ret) \
- return ret; \
-} while (0) \
-
-static inline int
-ath5k_register_mode(struct ieee80211_hw *hw, u8 m)
-{
- struct ath5k_softc *sc = hw->priv;
- struct ieee80211_hw_mode *modes = sc->modes;
- unsigned int i;
- int ret;
-
- if (!test_bit(m, sc->ah->ah_capabilities.cap_mode))
- return 0;
-
- for (i = 0; i < NUM_DRIVER_MODES; i++) {
- if (modes[i].mode != m || !modes[i].num_channels)
- continue;
- ret = ieee80211_register_hwmode(hw, &modes[i]);
- if (ret) {
- ATH5K_ERR(sc, "can't register hwmode %u\n", m);
- return ret;
- }
- return 0;
- }
- BUG();
-}
-
static int
ath5k_getchannels(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
- struct ieee80211_hw_mode *modes = sc->modes;
- unsigned int i, max_r, max_c;
- int ret;
-
- BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 3);
+ struct ieee80211_supported_band *sbands = sc->sbands;
+ const struct ath5k_rate_table *hw_rates;
+ unsigned int max_r, max_c, count_r, count_c;
+ int mode2g = AR5K_MODE_11G;
- /* The order here does not matter */
- modes[0].mode = MODE_IEEE80211G;
- modes[1].mode = MODE_IEEE80211B;
- modes[2].mode = MODE_IEEE80211A;
+ BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS);
max_r = ARRAY_SIZE(sc->rates);
max_c = ARRAY_SIZE(sc->channels);
+ count_r = count_c = 0;
+
+ /* 2GHz band */
+ if (!test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) {
+ mode2g = AR5K_MODE_11B;
+ if (!test_bit(AR5K_MODE_11B,
+ sc->ah->ah_capabilities.cap_mode))
+ mode2g = -1;
+ }
- for (i = 0; i < NUM_DRIVER_MODES; i++) {
- struct ieee80211_hw_mode *mode = &modes[i];
- const struct ath5k_rate_table *hw_rates;
+ if (mode2g > 0) {
+ struct ieee80211_supported_band *sband =
+ &sbands[IEEE80211_BAND_2GHZ];
- if (i == 0) {
- modes[0].rates = sc->rates;
- modes->channels = sc->channels;
- } else {
- struct ieee80211_hw_mode *prev_mode = &modes[i-1];
- int prev_num_r = prev_mode->num_rates;
- int prev_num_c = prev_mode->num_channels;
- mode->rates = &prev_mode->rates[prev_num_r];
- mode->channels = &prev_mode->channels[prev_num_c];
- }
+ sband->bitrates = sc->rates;
+ sband->channels = sc->channels;
+
+ sband->band = IEEE80211_BAND_2GHZ;
+ sband->n_channels = ath5k_copy_channels(ah, sband->channels,
+ mode2g, max_c);
+
+ hw_rates = ath5k_hw_get_rate_table(ah, mode2g);
+ sband->n_bitrates = ath5k_copy_rates(sband->bitrates,
+ hw_rates, max_r);
+
+ count_c = sband->n_channels;
+ count_r = sband->n_bitrates;
+
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+
+ max_r -= count_r;
+ max_c -= count_c;
- hw_rates = ath5k_hw_get_rate_table(ah, mode->mode);
- mode->num_rates = ath5k_copy_rates(mode->rates, hw_rates,
- max_r);
- mode->num_channels = ath5k_copy_channels(ah, mode->channels,
- mode->mode, max_c);
- max_r -= mode->num_rates;
- max_c -= mode->num_channels;
}
- /* We try to register all modes this driver supports. We don't bother
- * with MODE_IEEE80211B for AR5212 as MODE_IEEE80211G already accounts
- * for that as per mac80211. Then, REGISTER_MODE() will will actually
- * check the eeprom reading for more reliable capability information.
- * Order matters here as per mac80211's latest preference. This will
- * all hopefullly soon go away. */
+ /* 5GHz band */
- REGISTER_MODE(MODE_IEEE80211G);
- if (ah->ah_version != AR5K_AR5212)
- REGISTER_MODE(MODE_IEEE80211B);
- REGISTER_MODE(MODE_IEEE80211A);
+ if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) {
+ struct ieee80211_supported_band *sband =
+ &sbands[IEEE80211_BAND_5GHZ];
- ath5k_debug_dump_modes(sc, modes);
+ sband->bitrates = &sc->rates[count_r];
+ sband->channels = &sc->channels[count_c];
- return ret;
+ sband->band = IEEE80211_BAND_5GHZ;
+ sband->n_channels = ath5k_copy_channels(ah, sband->channels,
+ AR5K_MODE_11A, max_c);
+
+ hw_rates = ath5k_hw_get_rate_table(ah, AR5K_MODE_11A);
+ sband->n_bitrates = ath5k_copy_rates(sband->bitrates,
+ hw_rates, max_r);
+
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
+ }
+
+ ath5k_debug_dump_bands(sc);
+
+ return 0;
}
/*
struct ath5k_hw *ah = sc->ah;
int ret;
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "%u (%u MHz) -> %u (%u MHz)\n",
- sc->curchan->chan, sc->curchan->freq,
- chan->chan, chan->freq);
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n",
+ sc->curchan->center_freq, chan->center_freq);
+
+ if (chan->center_freq != sc->curchan->center_freq ||
+ chan->hw_value != sc->curchan->hw_value) {
+
+ sc->curchan = chan;
+ sc->curband = &sc->sbands[chan->band];
- if (chan->freq != sc->curchan->freq || chan->val != sc->curchan->val) {
/*
* To switch channels clear any pending DMA operations;
* wait long enough for the RX fifo to drain, reset the
ath5k_hw_set_intr(ah, 0); /* disable interrupts */
ath5k_txq_cleanup(sc); /* clear pending tx frames */
ath5k_rx_stop(sc); /* turn off frame recv */
- ret = ath5k_hw_reset(ah, sc->opmode, chan, true);
+ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
if (ret) {
- ATH5K_ERR(sc, "%s: unable to reset channel %u "
- "(%u Mhz)\n", __func__, chan->chan, chan->freq);
+ ATH5K_ERR(sc, "%s: unable to reset channel "
+ "(%u Mhz)\n", __func__, chan->center_freq);
return ret;
}
- sc->curchan = chan;
+
ath5k_hw_set_txpower_limit(sc->ah, 0);
/*
return 0;
}
+/*
+ * TODO: CLEAN THIS !!!
+ */
static void
ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
{
continue;
}
sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
- if (SHPREAMBLE_FLAG(ix) || rt->rates[ix].modulation ==
- IEEE80211_RATE_OFDM)
- sc->hwmap[i].txflags |=
- IEEE80211_RADIOTAP_F_SHORTPRE;
/* receive frames include FCS */
sc->hwmap[i].rxflags = sc->hwmap[i].txflags |
IEEE80211_RADIOTAP_F_FCS;
}
sc->curmode = mode;
+
+ if (mode == AR5K_MODE_11A) {
+ sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ];
+ } else {
+ sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ];
+ }
}
static void
ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
}
+/*
+ * Match the hw provided rate index (through descriptors)
+ * to an index for sc->curband->bitrates, so it can be used
+ * by the stack.
+ *
+ * This one is a little bit tricky but i think i'm right
+ * about this...
+ *
+ * We have 4 rate tables in the following order:
+ * XR (4 rates)
+ * 802.11a (8 rates)
+ * 802.11b (4 rates)
+ * 802.11g (12 rates)
+ * that make the hw rate table.
+ *
+ * Lets take a 5211 for example that supports a and b modes only.
+ * First comes the 802.11a table and then 802.11b (total 12 rates).
+ * When hw returns eg. 11 it points to the last 802.11b rate (11Mbit),
+ * if it returns 2 it points to the second 802.11a rate etc.
+ *
+ * Same goes for 5212 who has xr/a/b/g support (total 28 rates).
+ * First comes the XR table, then 802.11a, 802.11b and 802.11g.
+ * When hw returns eg. 27 it points to the last 802.11g rate (54Mbits) etc
+ */
+static void
+ath5k_set_total_hw_rates(struct ath5k_softc *sc) {
+
+ struct ath5k_hw *ah = sc->ah;
+
+ if (test_bit(AR5K_MODE_11A, ah->ah_modes))
+ sc->a_rates = 8;
+
+ if (test_bit(AR5K_MODE_11B, ah->ah_modes))
+ sc->b_rates = 4;
+
+ if (test_bit(AR5K_MODE_11G, ah->ah_modes))
+ sc->g_rates = 12;
+
+ /* XXX: Need to see what what happens when
+ xr disable bits in eeprom are set */
+ if (ah->ah_version >= AR5K_AR5212)
+ sc->xr_rates = 4;
+
+}
+
+static inline int
+ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) {
+
+ int mac80211_rix;
+
+ if(sc->curband->band == IEEE80211_BAND_2GHZ) {
+ /* We setup a g ratetable for both b/g modes */
+ mac80211_rix =
+ hw_rix - sc->b_rates - sc->a_rates - sc->xr_rates;
+ } else {
+ mac80211_rix = hw_rix - sc->xr_rates;
+ }
+
+ /* Something went wrong, fallback to basic rate for this band */
+ if ((mac80211_rix >= sc->curband->n_bitrates) ||
+ (mac80211_rix <= 0 ))
+ mac80211_rix = 1;
+
+ return mac80211_rix;
+}
+
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
- (ctl->power_level * 2), ctl->tx_rate, ctl->retry_limit, keyidx, 0, flags, 0, 0);
+ (sc->power_level * 2), ctl->tx_rate->hw_value,
+ ctl->retry_limit, keyidx, 0, flags, 0, 0);
if (ret)
goto err_unmap;
*/
spin_lock_bh(&txq->lock);
list_for_each_entry_safe(bf, bf0, &txq->q, list) {
- ath5k_debug_printtxbuf(sc, bf, !sc->ah->ah_proc_tx_desc(sc->ah,
- bf->desc));
+ ath5k_debug_printtxbuf(sc, bf);
ath5k_txbuf_free(sc, bf);
static unsigned int
ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
- struct sk_buff *skb)
+ struct sk_buff *skb, struct ath5k_rx_status *rs)
{
struct ieee80211_hdr *hdr = (void *)skb->data;
unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb);
- if (!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) &&
- ds->ds_rxstat.rs_keyix != AR5K_RXKEYIX_INVALID)
+ if (!(rs->rs_status & AR5K_RXERR_DECRYPT) &&
+ rs->rs_keyix != AR5K_RXKEYIX_INVALID)
return RX_FLAG_DECRYPTED;
/* Apparently when a default key is used to decrypt the packet
the hw does not set the index used to decrypt. In such cases
get the index from the packet. */
if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) &&
- !(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) &&
+ !(rs->rs_status & AR5K_RXERR_DECRYPT) &&
skb->len >= hlen + 4) {
keyix = skb->data[hlen + 3] >> 6;
static void
-ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb)
+ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
+ struct ieee80211_rx_status *rxs)
{
+ u64 tsf, bc_tstamp;
u32 hw_tu;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
- if ((mgmt->frame_control & IEEE80211_FCTL_FTYPE) ==
+ if ((le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_FTYPE) ==
IEEE80211_FTYPE_MGMT &&
- (mgmt->frame_control & IEEE80211_FCTL_STYPE) ==
+ (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) ==
IEEE80211_STYPE_BEACON &&
- mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS &&
+ le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
/*
- * Received an IBSS beacon with the same BSSID. Hardware might
- * have updated the TSF, check if we need to update timers.
+ * Received an IBSS beacon with the same BSSID. Hardware *must*
+ * have updated the local TSF. We have to work around various
+ * hardware bugs, though...
*/
- hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah));
- if (hw_tu >= sc->nexttbtt) {
- ath5k_beacon_update_timers(sc,
- mgmt->u.beacon.timestamp);
+ tsf = ath5k_hw_get_tsf64(sc->ah);
+ bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp);
+ hw_tu = TSF_TO_TU(tsf);
+
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+ "beacon %llx mactime %llx (diff %lld) tsf now %llx\n",
+ bc_tstamp, rxs->mactime,
+ (rxs->mactime - bc_tstamp), tsf);
+
+ /*
+ * Sometimes the HW will give us a wrong tstamp in the rx
+ * status, causing the timestamp extension to go wrong.
+ * (This seems to happen especially with beacon frames bigger
+ * than 78 byte (incl. FCS))
+ * But we know that the receive timestamp must be later than the
+ * timestamp of the beacon since HW must have synced to that.
+ *
+ * NOTE: here we assume mactime to be after the frame was
+ * received, not like mac80211 which defines it at the start.
+ */
+ if (bc_tstamp > rxs->mactime) {
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
- "detected HW merge from received beacon\n");
+ "fixing mactime from %llx to %llx\n",
+ rxs->mactime, tsf);
+ rxs->mactime = tsf;
}
+
+ /*
+ * Local TSF might have moved higher than our beacon timers,
+ * in that case we have to update them to continue sending
+ * beacons. This also takes care of synchronizing beacon sending
+ * times with other stations.
+ */
+ if (hw_tu >= sc->nexttbtt)
+ ath5k_beacon_update_timers(sc, bc_tstamp);
}
}
ath5k_tasklet_rx(unsigned long data)
{
struct ieee80211_rx_status rxs = {};
+ struct ath5k_rx_status rs = {};
struct sk_buff *skb;
struct ath5k_softc *sc = (void *)data;
struct ath5k_buf *bf;
struct ath5k_desc *ds;
- u16 len;
- u8 stat;
int ret;
int hdrlen;
int pad;
if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */
break;
- ret = sc->ah->ah_proc_rx_desc(sc->ah, ds);
+ ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
if (unlikely(ret == -EINPROGRESS))
break;
else if (unlikely(ret)) {
return;
}
- if (unlikely(ds->ds_rxstat.rs_more)) {
+ if (unlikely(rs.rs_more)) {
ATH5K_WARN(sc, "unsupported jumbo\n");
goto next;
}
- stat = ds->ds_rxstat.rs_status;
- if (unlikely(stat)) {
- if (stat & AR5K_RXERR_PHY)
+ if (unlikely(rs.rs_status)) {
+ if (rs.rs_status & AR5K_RXERR_PHY)
goto next;
- if (stat & AR5K_RXERR_DECRYPT) {
+ if (rs.rs_status & AR5K_RXERR_DECRYPT) {
/*
* Decrypt error. If the error occurred
* because there was no hardware key, then
*
* XXX do key cache faulting
*/
- if (ds->ds_rxstat.rs_keyix ==
- AR5K_RXKEYIX_INVALID &&
- !(stat & AR5K_RXERR_CRC))
+ if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
+ !(rs.rs_status & AR5K_RXERR_CRC))
goto accept;
}
- if (stat & AR5K_RXERR_MIC) {
+ if (rs.rs_status & AR5K_RXERR_MIC) {
rxs.flag |= RX_FLAG_MMIC_ERROR;
goto accept;
}
/* let crypto-error packets fall through in MNTR */
- if ((stat & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
+ if ((rs.rs_status &
+ ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
sc->opmode != IEEE80211_IF_TYPE_MNTR)
goto next;
}
accept:
- len = ds->ds_rxstat.rs_datalen;
- pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len,
- PCI_DMA_FROMDEVICE);
+ pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr,
+ rs.rs_datalen, PCI_DMA_FROMDEVICE);
pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
PCI_DMA_FROMDEVICE);
bf->skb = NULL;
- skb_put(skb, len);
+ skb_put(skb, rs.rs_datalen);
/*
* the hardware adds a padding to 4 byte boundaries between
* 15bit only. that means TSF extension has to be done within
* 32768usec (about 32ms). it might be necessary to move this to
* the interrupt handler, like it is done in madwifi.
+ *
+ * Unfortunately we don't know when the hardware takes the rx
+ * timestamp (beginning of phy frame, data frame, end of rx?).
+ * The only thing we know is that it is hardware specific...
+ * On AR5213 it seems the rx timestamp is at the end of the
+ * frame, but i'm not sure.
+ *
+ * NOTE: mac80211 defines mactime at the beginning of the first
+ * data symbol. Since we don't have any time references it's
+ * impossible to comply to that. This affects IBSS merge only
+ * right now, so it's not too bad...
*/
- rxs.mactime = ath5k_extend_tsf(sc->ah, ds->ds_rxstat.rs_tstamp);
+ rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
rxs.flag |= RX_FLAG_TSFT;
- rxs.freq = sc->curchan->freq;
- rxs.channel = sc->curchan->chan;
- rxs.phymode = sc->curmode;
+ rxs.freq = sc->curchan->center_freq;
+ rxs.band = sc->curband->band;
/*
* signal quality:
/* noise floor in dBm, from the last noise calibration */
rxs.noise = sc->ah->ah_noise_floor;
/* signal level in dBm */
- rxs.ssi = rxs.noise + ds->ds_rxstat.rs_rssi;
+ rxs.ssi = rxs.noise + rs.rs_rssi;
/*
* "signal" is actually displayed as Link Quality by iwconfig
* we provide a percentage based on rssi (assuming max rssi 64)
*/
- rxs.signal = ds->ds_rxstat.rs_rssi * 100 / 64;
+ rxs.signal = rs.rs_rssi * 100 / 64;
- rxs.antenna = ds->ds_rxstat.rs_antenna;
- rxs.rate = ds->ds_rxstat.rs_rate;
- rxs.flag |= ath5k_rx_decrypted(sc, ds, skb);
+ rxs.antenna = rs.rs_antenna;
+ rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
+ rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
ath5k_debug_dump_skb(sc, skb, "RX ", 0);
/* check beacons in IBSS mode */
if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
- ath5k_check_ibss_hw_merge(sc, skb);
+ ath5k_check_ibss_tsf(sc, skb, &rxs);
__ieee80211_rx(sc->hw, skb, &rxs);
- sc->led_rxrate = ds->ds_rxstat.rs_rate;
+ sc->led_rxrate = rs.rs_rate;
ath5k_led_event(sc, ATH_LED_RX);
next:
list_move_tail(&bf->list, &sc->rxbuf);
ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
{
struct ieee80211_tx_status txs = {};
+ struct ath5k_tx_status ts = {};
struct ath5k_buf *bf, *bf0;
struct ath5k_desc *ds;
struct sk_buff *skb;
/* TODO only one segment */
pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
sc->desc_len, PCI_DMA_FROMDEVICE);
- ret = sc->ah->ah_proc_tx_desc(sc->ah, ds);
+ ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
if (unlikely(ret == -EINPROGRESS))
break;
else if (unlikely(ret)) {
PCI_DMA_TODEVICE);
txs.control = bf->ctl;
- txs.retry_count = ds->ds_txstat.ts_shortretry +
- ds->ds_txstat.ts_longretry / 6;
- if (unlikely(ds->ds_txstat.ts_status)) {
+ txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
+ if (unlikely(ts.ts_status)) {
sc->ll_stats.dot11ACKFailureCount++;
- if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY)
+ if (ts.ts_status & AR5K_TXERR_XRETRY)
txs.excessive_retries = 1;
- else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT)
+ else if (ts.ts_status & AR5K_TXERR_FILT)
txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED;
} else {
txs.flags |= IEEE80211_TX_STATUS_ACK;
- txs.ack_signal = ds->ds_txstat.ts_rssi;
+ txs.ack_signal = ts.ts_rssi;
}
ieee80211_tx_status(sc->hw, skb, &txs);
ds->ds_data = bf->skbaddr;
ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb),
- AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1,
- AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0);
+ AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),
+ ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID,
+ antenna, flags, 0, 0);
if (ret)
goto err_unmap;
* beacon timer registers.
*
* This is called in a variety of situations, e.g. when a beacon is received,
- * when a HW merge has been detected, but also when an new IBSS is created or
+ * when a TSF update has been detected, but also when an new IBSS is created or
* when we otherwise know we have to update the timers, but we keep it in this
* function to have it all together in one place.
*/
* another AP to associate with.
*
* In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
- * interrupts to detect HW merges only.
+ * interrupts to detect TSF updates only.
*
* AP mode is missing.
*/
* hardware send the beacons automatically. We have to load it
* only once here.
* We use the SWBA interrupt only to keep track of the beacon
- * timers in order to detect HW merges (automatic TSF updates).
+ * timers in order to detect automatic TSF updates.
*/
ath5k_beaconq_config(sc);
* be followed by initialization of the appropriate bits
* and then setup of the interrupt mask.
*/
- sc->curchan = sc->hw->conf.chan;
+ sc->curchan = sc->hw->conf.channel;
+ sc->curband = &sc->sbands[sc->curchan->band];
ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false);
if (ret) {
ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret);
*
* In IBSS mode we use this interrupt just to
* keep track of the next TBTT (target beacon
- * transmission time) in order to detect hardware
- * merges (TSF updates).
+ * transmission time) in order to detect wether
+ * automatic TSF updates happened.
*/
if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
/* XXX: only if VEOL suppported */
struct ath5k_hw *ah = sc->ah;
ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
- sc->curchan->chan, sc->curchan->val);
+ ieee80211_frequency_to_channel(sc->curchan->center_freq),
+ sc->curchan->hw_value);
if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) {
/*
}
if (ath5k_hw_phy_calibrate(ah, sc->curchan))
ATH5K_ERR(sc, "calibration of channel %u failed\n",
- sc->curchan->chan);
+ ieee80211_frequency_to_channel(
+ sc->curchan->center_freq));
mod_timer(&sc->calib_tim, round_jiffies(jiffies +
msecs_to_jiffies(ath5k_calinterval * 1000)));
memmove(skb->data, skb->data+pad, hdrlen);
}
- sc->led_txrate = ctl->tx_rate;
+ sc->led_txrate = ctl->tx_rate->hw_value;
spin_lock_irqsave(&sc->txbuflock, flags);
if (list_empty(&sc->txbuf)) {
int ret;
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
- /*
- * Convert to a hw channel description with the flags
- * constrained to reflect the current operating mode.
- */
- sc->curchan = hw->conf.chan;
ath5k_hw_set_intr(ah, 0);
ath5k_txq_cleanup(sc);
mutex_unlock(&sc->lock);
}
+/*
+ * TODO: Phy disable/diversity etc
+ */
static int
ath5k_config(struct ieee80211_hw *hw,
struct ieee80211_conf *conf)
struct ath5k_softc *sc = hw->priv;
sc->bintval = conf->beacon_int;
- ath5k_setcurmode(sc, conf->phymode);
+ sc->power_level = conf->power_level;
- return ath5k_chan_set(sc, conf->chan);
+ return ath5k_chan_set(sc, conf->channel);
}
static int
switch(key->alg) {
case ALG_WEP:
- break;
+ /* XXX: fix hardware encryption, its not working. For now
+ * allow software encryption */
+ /* break; */
case ALG_TKIP:
case ALG_CCMP:
return -EOPNOTSUPP;
#if CHAN_DEBUG
#define ATH_CHAN_MAX (26+26+26+200+200)
#else
-#define ATH_CHAN_MAX (14+14+14+252+20) /* XXX what's the max? */
+#define ATH_CHAN_MAX (14+14+14+252+20)
#endif
/* Software Carrier, keeps track of the driver state
struct ieee80211_tx_queue_stats tx_stats;
struct ieee80211_low_level_stats ll_stats;
struct ieee80211_hw *hw; /* IEEE 802.11 common */
- struct ieee80211_hw_mode modes[NUM_DRIVER_MODES];
+ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
struct ieee80211_channel channels[ATH_CHAN_MAX];
- struct ieee80211_rate rates[AR5K_MAX_RATES * NUM_DRIVER_MODES];
+ struct ieee80211_rate rates[AR5K_MAX_RATES * IEEE80211_NUM_BANDS];
enum ieee80211_if_types opmode;
struct ath5k_hw *ah; /* Atheros HW */
-#if ATH5K_DEBUG
+ struct ieee80211_supported_band *curband;
+
+ u8 a_rates;
+ u8 b_rates;
+ u8 g_rates;
+ u8 xr_rates;
+
+#ifdef CONFIG_ATH5K_DEBUG
struct ath5k_dbg_info debug; /* debug info */
-#endif
+#endif /* CONFIG_ATH5K_DEBUG */
struct ath5k_buf *bufptr; /* allocated buffer ptr */
struct ath5k_desc *desc; /* TX/RX descriptors */
unsigned int nexttbtt; /* next beacon time in TU */
struct timer_list calib_tim; /* calibration timer */
+ int power_level; /* Requested tx power in dbm */
};
#define ath5k_hw_hasbssidmask(_ah) \
module_param_named(debug, ath5k_debug, uint, 0);
-#if ATH5K_DEBUG
+#ifdef CONFIG_ATH5K_DEBUG
#include <linux/seq_file.h>
#include "reg.h"
{
struct ath5k_softc *sc = file->private_data;
char buf[100];
- snprintf(buf, sizeof(buf), "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
+ snprintf(buf, sizeof(buf), "0x%016llx\n",
+ (unsigned long long)ath5k_hw_get_tsf64(sc->ah));
return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
}
tsf = ath5k_hw_get_tsf64(sc->ah);
len += snprintf(buf+len, sizeof(buf)-len,
- "TSF\t\t0x%016llx\tTU: %08x\n", tsf, TSF_TO_TU(tsf));
+ "TSF\t\t0x%016llx\tTU: %08x\n",
+ (unsigned long long)tsf, TSF_TO_TU(tsf));
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
{ ATH5K_DEBUG_LED, "led", "LED mamagement" },
{ ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" },
{ ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" },
- { ATH5K_DEBUG_DUMPMODES, "dumpmodes", "dump modes" },
+ { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" },
{ ATH5K_DEBUG_TRACE, "trace", "trace function calls" },
{ ATH5K_DEBUG_ANY, "all", "show all debug levels" },
};
/* functions used in other places */
void
-ath5k_debug_dump_modes(struct ath5k_softc *sc, struct ieee80211_hw_mode *modes)
+ath5k_debug_dump_bands(struct ath5k_softc *sc)
{
- unsigned int m, i;
+ unsigned int b, i;
- if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPMODES)))
+ if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPBANDS)))
return;
- for (m = 0; m < NUM_DRIVER_MODES; m++) {
- printk(KERN_DEBUG "Mode %u: channels %d, rates %d\n", m,
- modes[m].num_channels, modes[m].num_rates);
+ BUG_ON(!sc->sbands);
+
+ for (b = 0; b < IEEE80211_NUM_BANDS; b++) {
+ struct ieee80211_supported_band *band = &sc->sbands[b];
+ char bname[5];
+ switch (band->band) {
+ case IEEE80211_BAND_2GHZ:
+ strcpy(bname, "2 GHz");
+ break;
+ case IEEE80211_BAND_5GHZ:
+ strcpy(bname, "5 GHz");
+ break;
+ default:
+ printk(KERN_DEBUG "Band not supported: %d\n",
+ band->band);
+ return;
+ }
+ printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname,
+ band->n_channels, band->n_bitrates);
printk(KERN_DEBUG " channels:\n");
- for (i = 0; i < modes[m].num_channels; i++)
+ for (i = 0; i < band->n_channels; i++)
printk(KERN_DEBUG " %3d %d %.4x %.4x\n",
- modes[m].channels[i].chan,
- modes[m].channels[i].freq,
- modes[m].channels[i].val,
- modes[m].channels[i].flag);
+ ieee80211_frequency_to_channel(
+ band->channels[i].center_freq),
+ band->channels[i].center_freq,
+ band->channels[i].hw_value,
+ band->channels[i].flags);
printk(KERN_DEBUG " rates:\n");
- for (i = 0; i < modes[m].num_rates; i++)
+ for (i = 0; i < band->n_bitrates; i++)
printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n",
- modes[m].rates[i].rate,
- modes[m].rates[i].val,
- modes[m].rates[i].flags,
- modes[m].rates[i].val2);
+ band->bitrates[i].bitrate,
+ band->bitrates[i].hw_value,
+ band->bitrates[i].flags,
+ band->bitrates[i].hw_value_short);
}
}
static inline void
-ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done)
+ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done,
+ struct ath5k_rx_status *rs)
{
struct ath5k_desc *ds = bf->desc;
+ struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx;
printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n",
ds, (unsigned long long)bf->daddr,
- ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1,
- ds->ds_hw[0], ds->ds_hw[1],
- !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!');
+ ds->ds_link, ds->ds_data,
+ rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1,
+ rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0,
+ !done ? ' ' : (rs->rs_status == 0) ? '*' : '!');
}
void
{
struct ath5k_desc *ds;
struct ath5k_buf *bf;
+ struct ath5k_rx_status rs = {};
int status;
if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
spin_lock_bh(&sc->rxbuflock);
list_for_each_entry(bf, &sc->rxbuf, list) {
ds = bf->desc;
- status = ah->ah_proc_rx_desc(ah, ds);
+ status = ah->ah_proc_rx_desc(ah, ds, &rs);
if (!status)
- ath5k_debug_printrxbuf(bf, status == 0);
+ ath5k_debug_printrxbuf(bf, status == 0, &rs);
}
spin_unlock_bh(&sc->rxbuflock);
}
}
void
-ath5k_debug_printtxbuf(struct ath5k_softc *sc,
- struct ath5k_buf *bf, int done)
+ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf)
{
struct ath5k_desc *ds = bf->desc;
+ struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212;
+ struct ath5k_tx_status ts = {};
+ int done;
if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
return;
+ done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts);
+
printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x "
"%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link,
- ds->ds_data, ds->ds_ctl0, ds->ds_ctl1,
- ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3],
- !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!');
+ ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1,
+ td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3,
+ td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
+ done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
}
-#endif /* if ATH5K_DEBUG */
+#endif /* ifdef CONFIG_ATH5K_DEBUG */
#ifndef _ATH5K_DEBUG_H
#define _ATH5K_DEBUG_H
-/* set this to 1 for debugging output */
-#ifndef ATH5K_DEBUG
-#define ATH5K_DEBUG 0
-#endif
-
struct ath5k_softc;
struct ath5k_hw;
struct ieee80211_hw_mode;
* @ATH5K_DEBUG_LED: led management
* @ATH5K_DEBUG_DUMP_RX: print received skb content
* @ATH5K_DEBUG_DUMP_TX: print transmit skb content
- * @ATH5K_DEBUG_DUMPMODES: dump modes
+ * @ATH5K_DEBUG_DUMPBANDS: dump bands
* @ATH5K_DEBUG_TRACE: trace function calls
* @ATH5K_DEBUG_ANY: show at any debug level
*
ATH5K_DEBUG_LED = 0x00000080,
ATH5K_DEBUG_DUMP_RX = 0x00000100,
ATH5K_DEBUG_DUMP_TX = 0x00000200,
- ATH5K_DEBUG_DUMPMODES = 0x00000400,
+ ATH5K_DEBUG_DUMPBANDS = 0x00000400,
ATH5K_DEBUG_TRACE = 0x00001000,
ATH5K_DEBUG_ANY = 0xffffffff
};
-#if ATH5K_DEBUG
+#ifdef CONFIG_ATH5K_DEBUG
#define ATH5K_TRACE(_sc) do { \
if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \
ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
void
-ath5k_debug_dump_modes(struct ath5k_softc *sc,
- struct ieee80211_hw_mode *modes);
+ath5k_debug_dump_bands(struct ath5k_softc *sc);
void
ath5k_debug_dump_skb(struct ath5k_softc *sc,
struct sk_buff *skb, const char *prefix, int tx);
void
-ath5k_debug_printtxbuf(struct ath5k_softc *sc,
- struct ath5k_buf *bf, int done);
+ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf);
#else /* no debugging */
-#define ATH5K_TRACE(_sc) /* empty */
+#include <linux/compiler.h>
+
+#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc))
static inline void __attribute__ ((format (printf, 3, 4)))
ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {}
ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
static inline void
-ath5k_debug_dump_modes(struct ath5k_softc *sc,
- struct ieee80211_hw_mode *modes) {}
+ath5k_debug_dump_bands(struct ath5k_softc *sc) {}
static inline void
ath5k_debug_dump_skb(struct ath5k_softc *sc,
struct sk_buff *skb, const char *prefix, int tx) {}
static inline void
-ath5k_debug_printtxbuf(struct ath5k_softc *sc,
- struct ath5k_buf *bf, int done) {}
+ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {}
-#endif /* if ATH5K_DEBUG */
+#endif /* ifdef CONFIG_ATH5K_DEBUG */
#endif /* ifndef _ATH5K_DEBUG_H */
- /*
+/*
* Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
* Copyright (c) 2007 Matthew W. S. Bell <mentor@madwifi.org>
static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int);
-static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *,
+ struct ath5k_tx_status *);
static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int);
-static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
-static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *, struct ath5k_desc *);
-static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *,
+ struct ath5k_tx_status *);
+static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *, struct ath5k_desc *,
+ struct ath5k_rx_status *);
+static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *, struct ath5k_desc *,
+ struct ath5k_rx_status *);
static int ath5k_hw_get_capabilities(struct ath5k_hw *);
static int ath5k_eeprom_init(struct ath5k_hw *);
static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
{
- return turbo == true ? (usec * 80) : (usec * 40);
+ return turbo ? (usec * 80) : (usec * 40);
}
static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
{
- return turbo == true ? (clock / 80) : (clock / 40);
+ return turbo ? (clock / 80) : (clock / 40);
}
/*
for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
data = ath5k_hw_reg_read(ah, reg);
- if ((is_set == true) && (data & flag))
+ if (is_set && (data & flag))
break;
else if ((data & flag) == val)
break;
* HW information
*/
- /* Get reg domain from eeprom */
- ath5k_get_regdomain(ah);
-
ah->ah_op_mode = IEEE80211_IF_TYPE_STA;
ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
ah->ah_turbo = false;
}
if (ah->ah_version == AR5K_AR5212)
- ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status;
+ ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
else if (ah->ah_version <= AR5K_AR5211)
- ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status;
+ ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
/* Bring device out of sleep and reset it's units */
ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true);
/* Identify single chip solutions */
if((srev <= AR5K_SREV_VER_AR5414) &&
- (srev >= AR5K_SREV_VER_AR2424)) {
+ (srev >= AR5K_SREV_VER_AR2413)) {
ah->ah_single_chip = true;
} else {
ah->ah_single_chip = false;
ah->ah_radio = AR5K_RF5110;
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
ah->ah_radio = AR5K_RF5111;
- } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
+ } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) {
+
ah->ah_radio = AR5K_RF5112;
+
+ if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
+ } else {
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+ }
+
+ } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
+ ah->ah_radio = AR5K_RF2413;
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
} else {
+
ah->ah_radio = AR5K_RF5413;
+
+ if (ah->ah_mac_srev <= AR5K_SREV_VER_AR5424 &&
+ ah->ah_mac_srev >= AR5K_SREV_VER_AR2424)
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424;
+ else if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2425)
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
+ else
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+
+
}
ah->ah_phy = AR5K_PHY(0);
*/
static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
{
- u32 turbo, mode, clock;
+ struct pci_dev *pdev = ah->ah_sc->pdev;
+ u32 turbo, mode, clock, bus_flags;
int ret;
turbo = 0;
AR5K_PHY_TURBO);
}
- /* ...reset chipset and PCI device */
- if (ah->ah_single_chip == false && ath5k_hw_nic_reset(ah,
- AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI)) {
+ /* reseting PCI on PCI-E cards results card to hang
+ * and always return 0xffff... so we ingore that flag
+ * for PCI-E cards */
+ bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+
+ /* Reset chipset */
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_BASEBAND | bus_flags);
+ if (ret) {
ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n");
return -EIO;
}
/* Get rate tables */
switch (mode) {
- case MODE_IEEE80211A:
+ case AR5K_MODE_11A:
return &ath5k_rt_11a;
- case MODE_ATHEROS_TURBO:
+ case AR5K_MODE_11A_TURBO:
return &ath5k_rt_turbo;
- case MODE_IEEE80211B:
+ case AR5K_MODE_11B:
return &ath5k_rt_11b;
- case MODE_IEEE80211G:
+ case AR5K_MODE_11G:
return &ath5k_rt_11g;
- case MODE_ATHEROS_TURBOG:
+ case AR5K_MODE_11G_TURBO:
return &ath5k_rt_xr;
}
ds_coef_exp, ds_coef_man, clock;
if (!(ah->ah_version == AR5K_AR5212) ||
- !(channel->val & CHANNEL_OFDM))
+ !(channel->hw_value & CHANNEL_OFDM))
BUG();
/* Seems there are two PLLs, one for baseband sampling and one
* for tuning. Tuning basebands are 40 MHz or 80MHz when in
* turbo. */
- clock = channel->val & CHANNEL_TURBO ? 80 : 40;
+ clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40;
coef_scaled = ((5 * (clock << 24)) / 2) /
- channel->freq;
+ channel->center_freq;
for (coef_exp = 31; coef_exp > 0; coef_exp--)
if ((coef_scaled >> coef_exp) & 0x1)
* ath5k_hw_write_rate_duration - set rate duration during hw resets
*
* @ah: the &struct ath5k_hw
- * @driver_mode: one of enum ieee80211_phymode or our one of our own
- * vendor modes
+ * @mode: one of enum ath5k_driver_mode
*
* Write the rate duration table for the current mode upon hw reset. This
* is a helper for ath5k_hw_reset(). It seems all this is doing is setting
*
*/
static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
- unsigned int driver_mode)
+ unsigned int mode)
{
struct ath5k_softc *sc = ah->ah_sc;
const struct ath5k_rate_table *rt;
+ struct ieee80211_rate srate = {};
unsigned int i;
/* Get rate table for the current operating mode */
- rt = ath5k_hw_get_rate_table(ah,
- driver_mode);
+ rt = ath5k_hw_get_rate_table(ah, mode);
/* Write rate duration table */
for (i = 0; i < rt->rate_count; i++) {
const struct ath5k_rate *rate, *control_rate;
+
u32 reg;
u16 tx_time;
/* Set ACK timeout */
reg = AR5K_RATE_DUR(rate->rate_code);
+ srate.bitrate = control_rate->rate_kbps/100;
+
/* An ACK frame consists of 10 bytes. If you add the FCS,
* which ieee80211_generic_frame_duration() adds,
* its 14 bytes. Note we use the control rate and not the
* actual rate for this rate. See mac80211 tx.c
* ieee80211_duration() for a brief description of
* what rate we should choose to TX ACKs. */
- tx_time = ieee80211_generic_frame_duration(sc->hw,
- sc->vif, 10, control_rate->rate_kbps/100);
+ tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
+ sc->vif, 10, &srate));
ath5k_hw_reg_write(ah, tx_time, reg);
struct ieee80211_channel *channel, bool change_channel)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- u32 data, s_seq, s_ant, s_led[3];
- unsigned int i, mode, freq, ee_mode, ant[2], driver_mode = -1;
+ struct pci_dev *pdev = ah->ah_sc->pdev;
+ u32 data, s_seq, s_ant, s_led[3], dma_size;
+ unsigned int i, mode, freq, ee_mode, ant[2];
int ret;
ATH5K_TRACE(ah->ah_sc);
*/
/*DCU/Antenna selection not available on 5210*/
if (ah->ah_version != AR5K_AR5210) {
- if (change_channel == true) {
+ if (change_channel) {
/* Seq number for queue 0 -do this for all queues ? */
s_seq = ath5k_hw_reg_read(ah,
AR5K_QUEUE_DFS_SEQNUM(0));
s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
- if (change_channel == true && ah->ah_rf_banks != NULL)
+ if (change_channel && ah->ah_rf_banks != NULL)
ath5k_hw_get_rf_gain(ah);
/*Wakeup the device*/
- ret = ath5k_hw_nic_wakeup(ah, channel->val, false);
+ ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
if (ret)
return ret;
if (ah->ah_version != AR5K_AR5210) {
if (ah->ah_radio != AR5K_RF5111 &&
ah->ah_radio != AR5K_RF5112 &&
- ah->ah_radio != AR5K_RF5413) {
+ ah->ah_radio != AR5K_RF5413 &&
+ ah->ah_radio != AR5K_RF2413) {
ATH5K_ERR(ah->ah_sc,
"invalid phy radio: %u\n", ah->ah_radio);
return -EINVAL;
}
- switch (channel->val & CHANNEL_MODES) {
+ switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
- mode = AR5K_INI_VAL_11A;
+ mode = AR5K_MODE_11A;
freq = AR5K_INI_RFGAIN_5GHZ;
ee_mode = AR5K_EEPROM_MODE_11A;
- driver_mode = MODE_IEEE80211A;
break;
case CHANNEL_G:
- mode = AR5K_INI_VAL_11G;
+ mode = AR5K_MODE_11G;
freq = AR5K_INI_RFGAIN_2GHZ;
ee_mode = AR5K_EEPROM_MODE_11G;
- driver_mode = MODE_IEEE80211G;
break;
case CHANNEL_B:
- mode = AR5K_INI_VAL_11B;
+ mode = AR5K_MODE_11B;
freq = AR5K_INI_RFGAIN_2GHZ;
ee_mode = AR5K_EEPROM_MODE_11B;
- driver_mode = MODE_IEEE80211B;
break;
case CHANNEL_T:
- mode = AR5K_INI_VAL_11A_TURBO;
+ mode = AR5K_MODE_11A_TURBO;
freq = AR5K_INI_RFGAIN_5GHZ;
ee_mode = AR5K_EEPROM_MODE_11A;
- driver_mode = MODE_ATHEROS_TURBO;
break;
/*Is this ok on 5211 too ?*/
case CHANNEL_TG:
- mode = AR5K_INI_VAL_11G_TURBO;
+ mode = AR5K_MODE_11G_TURBO;
freq = AR5K_INI_RFGAIN_2GHZ;
ee_mode = AR5K_EEPROM_MODE_11G;
- driver_mode = MODE_ATHEROS_TURBOG;
break;
case CHANNEL_XR:
if (ah->ah_version == AR5K_AR5211) {
"XR mode not available on 5211");
return -EINVAL;
}
- mode = AR5K_INI_VAL_XR;
+ mode = AR5K_MODE_XR;
freq = AR5K_INI_RFGAIN_5GHZ;
ee_mode = AR5K_EEPROM_MODE_11A;
- driver_mode = MODE_IEEE80211A;
break;
default:
ATH5K_ERR(ah->ah_sc,
- "invalid channel: %d\n", channel->freq);
+ "invalid channel: %d\n", channel->center_freq);
return -EINVAL;
}
/*
* Write some more initial register settings
*/
- if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */
+ if (ah->ah_version == AR5K_AR5212) {
ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11));
- if (channel->val == CHANNEL_G)
- ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */
+ if (channel->hw_value == CHANNEL_G)
+ if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413)
+ ath5k_hw_reg_write(ah, 0x00f80d80,
+ AR5K_PHY(83));
+ else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424)
+ ath5k_hw_reg_write(ah, 0x00380140,
+ AR5K_PHY(83));
+ else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425)
+ ath5k_hw_reg_write(ah, 0x00fc0ec0,
+ AR5K_PHY(83));
+ else /* 2425 */
+ ath5k_hw_reg_write(ah, 0x00fc0fc0,
+ AR5K_PHY(83));
else
- ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83));
+ ath5k_hw_reg_write(ah, 0x00000000,
+ AR5K_PHY(83));
- ath5k_hw_reg_write(ah, 0x000001b5, 0xa228); /* 0x000009b5 */
ath5k_hw_reg_write(ah, 0x000009b5, 0xa228);
ath5k_hw_reg_write(ah, 0x0000000f, 0x8060);
ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
AR5K_SREV_RAD_5112A) {
ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
AR5K_PHY_CCKTXCTL);
- if (channel->val & CHANNEL_5GHZ)
+ if (channel->hw_value & CHANNEL_5GHZ)
data = 0xffb81020;
else
data = 0xffb80d20;
* mac80211 are integrated */
if (ah->ah_version == AR5K_AR5212 &&
ah->ah_sc->vif != NULL)
- ath5k_hw_write_rate_duration(ah, driver_mode);
+ ath5k_hw_write_rate_duration(ah, mode);
/*
* Write RF registers
/* Write OFDM timings on 5212*/
if (ah->ah_version == AR5K_AR5212 &&
- channel->val & CHANNEL_OFDM) {
+ channel->hw_value & CHANNEL_OFDM) {
ret = ath5k_hw_write_ofdm_timings(ah, channel);
if (ret)
return ret;
/*Enable/disable 802.11b mode on 5111
(enable 2111 frequency converter + CCK)*/
if (ah->ah_radio == AR5K_RF5111) {
- if (driver_mode == MODE_IEEE80211B)
+ if (mode == AR5K_MODE_11B)
AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
AR5K_TXCFG_B_MODE);
else
/*
* Set Rx/Tx DMA Configuration
- *(passing dma size not available on 5210)
+ *
+ * Set maximum DMA size (512) except for PCI-E cards since
+ * it causes rx overruns and tx errors (tested on 5424 but since
+ * rx overruns also occur on 5416/5418 with madwifi we set 128
+ * for all PCI-E cards to be safe).
+ *
+ * In dumps this is 128 for allchips.
+ *
+ * XXX: need to check 5210 for this
+ * TODO: Check out tx triger level, it's always 64 on dumps but I
+ * guess we can tweak it and see how it goes ;-)
*/
+ dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B;
if (ah->ah_version != AR5K_AR5210) {
- AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR,
- AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE);
- AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_SDMAMW,
- AR5K_DMASIZE_512B);
+ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+ AR5K_TXCFG_SDMAMR, dma_size);
+ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+ AR5K_RXCFG_SDMAMW, dma_size);
}
/*
if (ah->ah_version != AR5K_AR5210) {
data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
AR5K_PHY_RX_DELAY_M;
- data = (channel->val & CHANNEL_CCK) ?
+ data = (channel->hw_value & CHANNEL_CCK) ?
((data << 2) / 22) : (data / 10);
udelay(100 + data);
if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_CAL, 0, false)) {
ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
- channel->freq);
+ channel->center_freq);
return -EAGAIN;
}
- ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
+ ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
if (ret)
return ret;
/* A and G modes can use QAM modulation which requires enabling
* I and Q calibration. Don't bother in B mode. */
- if (!(driver_mode == MODE_IEEE80211B)) {
+ if (!(mode == AR5K_MODE_11B)) {
ah->ah_calibration = true;
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
/*
* Set the 32MHz reference clock on 5212 phy clock sleep register
+ *
+ * TODO: Find out how to switch to external 32Khz clock to save power
*/
if (ah->ah_version == AR5K_AR5212) {
ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL);
ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
- ath5k_hw_reg_write(ah, ah->ah_radio == AR5K_RF5111 ?
- AR5K_PHY_SPENDING_RF5111 : AR5K_PHY_SPENDING_RF5112,
- AR5K_PHY_SPENDING);
+ ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
+ }
+
+ if (ah->ah_version == AR5K_AR5212) {
+ ath5k_hw_reg_write(ah, 0x000100aa, 0x8118);
+ ath5k_hw_reg_write(ah, 0x00003210, 0x811c);
+ ath5k_hw_reg_write(ah, 0x00000052, 0x8108);
+ if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413)
+ ath5k_hw_reg_write(ah, 0x00000004, 0x8120);
}
/*
staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
/* fallthrough */
case AR5K_PM_NETWORK_SLEEP:
- if (set_chip == true)
+ if (set_chip)
ath5k_hw_reg_write(ah,
AR5K_SLEEP_CTL_SLE | sleep_duration,
AR5K_SLEEP_CTL);
break;
case AR5K_PM_FULL_SLEEP:
- if (set_chip == true)
+ if (set_chip)
ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
AR5K_SLEEP_CTL);
break;
case AR5K_PM_AWAKE:
- if (set_chip == false)
+ if (!set_chip)
goto commit;
ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
AR5K_TXCFG_TXFULL);
- if (increase == false) {
+ if (!increase) {
if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
goto done;
} else
/*
* Write to eeprom - currently disabled, use at your own risk
*/
+#if 0
static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data)
{
-#if 0
+
u32 status, timeout;
ATH5K_TRACE(ah->ah_sc);
}
udelay(15);
}
-#endif
+
ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!");
return -EIO;
}
+#endif
/*
* Translate binary channel representation in EEPROM to frequency
}
/*
- * Read/Write regulatory domain
- */
-static bool ath5k_eeprom_regulation_domain(struct ath5k_hw *ah, bool write,
- enum ath5k_regdom *regdomain)
-{
- u16 ee_regdomain;
-
- /* Read current value */
- if (write != true) {
- ee_regdomain = ah->ah_capabilities.cap_eeprom.ee_regdomain;
- *regdomain = ath5k_regdom_to_ieee(ee_regdomain);
- return true;
- }
-
- ee_regdomain = ath5k_regdom_from_ieee(*regdomain);
-
- /* Try to write a new value */
- if (ah->ah_capabilities.cap_eeprom.ee_protect &
- AR5K_EEPROM_PROTECT_WR_128_191)
- return false;
- if (ath5k_hw_eeprom_write(ah, AR5K_EEPROM_REG_DOMAIN, ee_regdomain)!=0)
- return false;
-
- ah->ah_capabilities.cap_eeprom.ee_regdomain = ee_regdomain;
-
- return true;
-}
-
-/*
- * Use the above to write a new regulatory domain
- */
-int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain)
-{
- enum ath5k_regdom ieee_regdomain;
-
- ieee_regdomain = ath5k_regdom_to_ieee(regdomain);
-
- if (ath5k_eeprom_regulation_domain(ah, true, &ieee_regdomain) == true)
- return 0;
-
- return -EIO;
-}
-
-/*
* Fill the capabilities struct
*/
static int ath5k_hw_get_capabilities(struct ath5k_hw *ah)
ah->ah_capabilities.cap_range.range_2ghz_max = 0;
/* Set supported modes */
- __set_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode);
- __set_bit(MODE_ATHEROS_TURBO, ah->ah_capabilities.cap_mode);
+ __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode);
+ __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode);
} else {
/*
* XXX The tranceiver supports frequencies from 4920 to 6100GHz
ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
/* Set supported modes */
- __set_bit(MODE_IEEE80211A,
+ __set_bit(AR5K_MODE_11A,
ah->ah_capabilities.cap_mode);
- __set_bit(MODE_ATHEROS_TURBO,
+ __set_bit(AR5K_MODE_11A_TURBO,
ah->ah_capabilities.cap_mode);
if (ah->ah_version == AR5K_AR5212)
- __set_bit(MODE_ATHEROS_TURBOG,
+ __set_bit(AR5K_MODE_11G_TURBO,
ah->ah_capabilities.cap_mode);
}
ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
if (AR5K_EEPROM_HDR_11B(ee_header))
- __set_bit(MODE_IEEE80211B,
+ __set_bit(AR5K_MODE_11B,
ah->ah_capabilities.cap_mode);
if (AR5K_EEPROM_HDR_11G(ee_header))
- __set_bit(MODE_IEEE80211G,
+ __set_bit(AR5K_MODE_11G,
ah->ah_capabilities.cap_mode);
}
}
* Set simple BSSID mask on 5212
*/
if (ah->ah_version == AR5K_AR5212) {
- ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM0);
- ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM1);
+ ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0);
+ ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1);
}
/*
{
ATH5K_TRACE(ah->ah_sc);
AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+
+ /* TODO: ANI Support */
}
/*
{
ATH5K_TRACE(ah->ah_sc);
AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+
+ /* TODO: ANI Support */
}
/*
return 0;
/* Set Slot time */
- ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+ ath5k_hw_reg_write(ah, ah->ah_turbo ?
AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
AR5K_SLOT_TIME);
/* Set ACK_CTS timeout */
- ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+ ath5k_hw_reg_write(ah, ah->ah_turbo ?
AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
/* Set Transmit Latency */
- ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+ ath5k_hw_reg_write(ah, ah->ah_turbo ?
AR5K_INIT_TRANSMIT_LATENCY_TURBO :
AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
/* Set IFS0 */
- if (ah->ah_turbo == true)
+ if (ah->ah_turbo)
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
(ah->ah_aifs + tq->tqi_aifs) *
AR5K_INIT_SLOT_TIME_TURBO) <<
AR5K_INIT_SIFS, AR5K_IFS0);
/* Set IFS1 */
- ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+ ath5k_hw_reg_write(ah, ah->ah_turbo ?
AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
/* Set PHY register 0x9844 (??) */
- ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+ ath5k_hw_reg_write(ah, ah->ah_turbo ?
(ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 :
(ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C,
AR5K_PHY(17));
/* Set Frame Control Register */
- ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+ ath5k_hw_reg_write(ah, ah->ah_turbo ?
(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
AR5K_PHY_TURBO_SHORT | 0x2020) :
(AR5K_PHY_FRAME_CTL_INI | 0x1020),
/*
* Calculate and set retry limits
*/
- if (ah->ah_software_retry == true) {
+ if (ah->ah_software_retry) {
/* XXX Need to test this */
retry_lg = ah->ah_limit_tx_retries;
retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
unsigned int rtscts_rate, unsigned int rtscts_duration)
{
u32 frame_type;
- struct ath5k_hw_2w_tx_desc *tx_desc;
+ struct ath5k_hw_2w_tx_ctl *tx_ctl;
unsigned int frame_len;
- tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
+ tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
/*
* Validate input
return -EINVAL;
}
- /* Clear status descriptor */
- memset(desc->ds_hw, 0, sizeof(struct ath5k_hw_tx_status));
-
- /* Initialize control descriptor */
- tx_desc->tx_control_0 = 0;
- tx_desc->tx_control_1 = 0;
+ /* Clear descriptor */
+ memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
/* Setup control descriptor */
if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL;
- tx_desc->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+ tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */
if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL;
- tx_desc->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+ tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
/*
* Verify and set header length
if (ah->ah_version == AR5K_AR5210) {
if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
return -EINVAL;
- tx_desc->tx_control_0 |=
+ tx_ctl->tx_control_0 |=
AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
}
frame_type = type /*<< 2 ?*/;
}
- tx_desc->tx_control_0 |=
+ tx_ctl->tx_control_0 |=
AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
} else {
- tx_desc->tx_control_0 |=
+ tx_ctl->tx_control_0 |=
AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
- tx_desc->tx_control_1 |=
+ tx_ctl->tx_control_1 |=
AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
}
#define _TX_FLAGS(_c, _flag) \
if (flags & AR5K_TXDESC_##_flag) \
- tx_desc->tx_control_##_c |= \
+ tx_ctl->tx_control_##_c |= \
AR5K_2W_TX_DESC_CTL##_c##_##_flag
_TX_FLAGS(0, CLRDMASK);
* WEP crap
*/
if (key_index != AR5K_TXKEYIX_INVALID) {
- tx_desc->tx_control_0 |=
+ tx_ctl->tx_control_0 |=
AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
- tx_desc->tx_control_1 |=
+ tx_ctl->tx_control_1 |=
AR5K_REG_SM(key_index,
AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
}
*/
if ((ah->ah_version == AR5K_AR5210) &&
(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
- tx_desc->tx_control_1 |= rtscts_duration &
+ tx_ctl->tx_control_1 |= rtscts_duration &
AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
return 0;
unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate,
unsigned int rtscts_duration)
{
- struct ath5k_hw_4w_tx_desc *tx_desc;
- struct ath5k_hw_tx_status *tx_status;
+ struct ath5k_hw_4w_tx_ctl *tx_ctl;
unsigned int frame_len;
ATH5K_TRACE(ah->ah_sc);
- tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
- tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2];
+ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
/*
* Validate input
return -EINVAL;
}
- /* Clear status descriptor */
- memset(tx_status, 0, sizeof(struct ath5k_hw_tx_status));
-
- /* Initialize control descriptor */
- tx_desc->tx_control_0 = 0;
- tx_desc->tx_control_1 = 0;
- tx_desc->tx_control_2 = 0;
- tx_desc->tx_control_3 = 0;
+ /* Clear descriptor */
+ memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
/* Setup control descriptor */
if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL;
- tx_desc->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+ tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */
if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL;
- tx_desc->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+ tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
- tx_desc->tx_control_0 |=
+ tx_ctl->tx_control_0 |=
AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
- tx_desc->tx_control_1 |= AR5K_REG_SM(type,
+ tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
- tx_desc->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
+ tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
- tx_desc->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+ tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
#define _TX_FLAGS(_c, _flag) \
if (flags & AR5K_TXDESC_##_flag) \
- tx_desc->tx_control_##_c |= \
+ tx_ctl->tx_control_##_c |= \
AR5K_4W_TX_DESC_CTL##_c##_##_flag
_TX_FLAGS(0, CLRDMASK);
* WEP crap
*/
if (key_index != AR5K_TXKEYIX_INVALID) {
- tx_desc->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
- tx_desc->tx_control_1 |= AR5K_REG_SM(key_index,
+ tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+ tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
}
if ((flags & AR5K_TXDESC_RTSENA) &&
(flags & AR5K_TXDESC_CTSENA))
return -EINVAL;
- tx_desc->tx_control_2 |= rtscts_duration &
+ tx_ctl->tx_control_2 |= rtscts_duration &
AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
- tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+ tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
}
unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2,
unsigned int tx_rate3, u_int tx_tries3)
{
- struct ath5k_hw_4w_tx_desc *tx_desc;
+ struct ath5k_hw_4w_tx_ctl *tx_ctl;
/*
* Rates can be 0 as long as the retry count is 0 too.
}
if (ah->ah_version == AR5K_AR5212) {
- tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
+ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
#define _XTX_TRIES(_n) \
if (tx_tries##_n) { \
- tx_desc->tx_control_2 |= \
+ tx_ctl->tx_control_2 |= \
AR5K_REG_SM(tx_tries##_n, \
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \
- tx_desc->tx_control_3 |= \
+ tx_ctl->tx_control_3 |= \
AR5K_REG_SM(tx_rate##_n, \
AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \
}
* Proccess the tx status descriptor on 5210/5211
*/
static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
- struct ath5k_desc *desc)
+ struct ath5k_desc *desc, struct ath5k_tx_status *ts)
{
+ struct ath5k_hw_2w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status;
- struct ath5k_hw_2w_tx_desc *tx_desc;
- tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
- tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[0];
+ ATH5K_TRACE(ah->ah_sc);
+
+ tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
+ tx_status = &desc->ud.ds_tx5210.tx_stat;
/* No frame has been send or error */
if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
/*
* Get descriptor status
*/
- desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
- desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
- desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
- /*TODO: desc->ds_us.tx.ts_virtcol + test*/
- desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+ /*TODO: ts->ts_virtcol + test*/
+ ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
AR5K_DESC_TX_STATUS1_SEQ_NUM);
- desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+ ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
- desc->ds_us.tx.ts_antenna = 1;
- desc->ds_us.tx.ts_status = 0;
- desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0,
+ ts->ts_antenna = 1;
+ ts->ts_status = 0;
+ ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0,
AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
if (tx_status->tx_status_0 &
AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
- desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY;
+ ts->ts_status |= AR5K_TXERR_XRETRY;
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
- desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO;
+ ts->ts_status |= AR5K_TXERR_FIFO;
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
- desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT;
+ ts->ts_status |= AR5K_TXERR_FILT;
}
return 0;
* Proccess a tx descriptor on 5212
*/
static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
- struct ath5k_desc *desc)
+ struct ath5k_desc *desc, struct ath5k_tx_status *ts)
{
+ struct ath5k_hw_4w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status;
- struct ath5k_hw_4w_tx_desc *tx_desc;
ATH5K_TRACE(ah->ah_sc);
- tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
- tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2];
+
+ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+ tx_status = &desc->ud.ds_tx5212.tx_stat;
/* No frame has been send or error */
if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
/*
* Get descriptor status
*/
- desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
- desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
- desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
- desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+ ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
AR5K_DESC_TX_STATUS1_SEQ_NUM);
- desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+ ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
- desc->ds_us.tx.ts_antenna = (tx_status->tx_status_1 &
+ ts->ts_antenna = (tx_status->tx_status_1 &
AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
- desc->ds_us.tx.ts_status = 0;
+ ts->ts_status = 0;
switch (AR5K_REG_MS(tx_status->tx_status_1,
AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) {
case 0:
- desc->ds_us.tx.ts_rate = tx_desc->tx_control_3 &
+ ts->ts_rate = tx_ctl->tx_control_3 &
AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
break;
case 1:
- desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+ ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
- desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+ ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
break;
case 2:
- desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+ ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
- desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+ ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
break;
case 3:
- desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+ ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
- desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+ ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
break;
}
if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
if (tx_status->tx_status_0 &
AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
- desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY;
+ ts->ts_status |= AR5K_TXERR_XRETRY;
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
- desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO;
+ ts->ts_status |= AR5K_TXERR_FIFO;
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
- desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT;
+ ts->ts_status |= AR5K_TXERR_FILT;
}
return 0;
int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
u32 size, unsigned int flags)
{
- struct ath5k_rx_desc *rx_desc;
+ struct ath5k_hw_rx_ctl *rx_ctl;
ATH5K_TRACE(ah->ah_sc);
- rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0;
+ rx_ctl = &desc->ud.ds_rx.rx_ctl;
/*
- *Clear ds_hw
+ * Clear the descriptor
* If we don't clean the status descriptor,
* while scanning we get too many results,
* most of them virtual, after some secs
* of scanning system hangs. M.F.
*/
- memset(desc->ds_hw, 0, sizeof(desc->ds_hw));
-
- /*Initialize rx descriptor*/
- rx_desc->rx_control_0 = 0;
- rx_desc->rx_control_1 = 0;
+ memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
/* Setup descriptor */
- rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
- if (unlikely(rx_desc->rx_control_1 != size))
+ rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
+ if (unlikely(rx_ctl->rx_control_1 != size))
return -EINVAL;
if (flags & AR5K_RXDESC_INTREQ)
- rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
+ rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
return 0;
}
/*
* Proccess the rx status descriptor on 5210/5211
*/
-static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah,
- struct ath5k_desc *desc)
+static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
+ struct ath5k_desc *desc, struct ath5k_rx_status *rs)
{
- struct ath5k_hw_old_rx_status *rx_status;
+ struct ath5k_hw_rx_status *rx_status;
- rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0];
+ rx_status = &desc->ud.ds_rx.u.rx_stat;
/* No frame received / not ready */
- if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE)
+ if (unlikely((rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE)
== 0))
return -EINPROGRESS;
/*
* Frame receive status
*/
- desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 &
- AR5K_OLD_RX_DESC_STATUS0_DATA_LEN;
- desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
- AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL);
- desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
- AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE);
- desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 &
- AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA;
- desc->ds_us.rx.rs_more = rx_status->rx_status_0 &
- AR5K_OLD_RX_DESC_STATUS0_MORE;
- desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
- AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
- desc->ds_us.rx.rs_status = 0;
+ rs->rs_datalen = rx_status->rx_status_0 &
+ AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
+ rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+ AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+ rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+ AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
+ rs->rs_antenna = rx_status->rx_status_0 &
+ AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA;
+ rs->rs_more = rx_status->rx_status_0 &
+ AR5K_5210_RX_DESC_STATUS0_MORE;
+ /* TODO: this timestamp is 13 bit, later on we assume 15 bit */
+ rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+ AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+ rs->rs_status = 0;
/*
* Key table status
*/
- if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID)
- desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
- AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX);
+ if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID)
+ rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+ AR5K_5210_RX_DESC_STATUS1_KEY_INDEX);
else
- desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
+ rs->rs_keyix = AR5K_RXKEYIX_INVALID;
/*
* Receive/descriptor errors
*/
- if ((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK)
- == 0) {
- if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR)
- desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC;
+ if ((rx_status->rx_status_1 &
+ AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
+ if (rx_status->rx_status_1 &
+ AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
+ rs->rs_status |= AR5K_RXERR_CRC;
if (rx_status->rx_status_1 &
- AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN)
- desc->ds_us.rx.rs_status |= AR5K_RXERR_FIFO;
+ AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
+ rs->rs_status |= AR5K_RXERR_FIFO;
if (rx_status->rx_status_1 &
- AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR) {
- desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY;
- desc->ds_us.rx.rs_phyerr =
- AR5K_REG_MS(rx_status->rx_status_1,
- AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR);
+ AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
+ rs->rs_status |= AR5K_RXERR_PHY;
+ rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
+ AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
}
if (rx_status->rx_status_1 &
- AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
- desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT;
+ AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+ rs->rs_status |= AR5K_RXERR_DECRYPT;
}
return 0;
/*
* Proccess the rx status descriptor on 5212
*/
-static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah,
- struct ath5k_desc *desc)
+static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
+ struct ath5k_desc *desc, struct ath5k_rx_status *rs)
{
- struct ath5k_hw_new_rx_status *rx_status;
+ struct ath5k_hw_rx_status *rx_status;
struct ath5k_hw_rx_error *rx_err;
ATH5K_TRACE(ah->ah_sc);
- rx_status = (struct ath5k_hw_new_rx_status *)&desc->ds_hw[0];
+ rx_status = &desc->ud.ds_rx.u.rx_stat;
/* Overlay on error */
- rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0];
+ rx_err = &desc->ud.ds_rx.u.rx_err;
/* No frame received / not ready */
- if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE)
+ if (unlikely((rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE)
== 0))
return -EINPROGRESS;
/*
* Frame receive status
*/
- desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 &
- AR5K_NEW_RX_DESC_STATUS0_DATA_LEN;
- desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
- AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL);
- desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
- AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE);
- desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 &
- AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA;
- desc->ds_us.rx.rs_more = rx_status->rx_status_0 &
- AR5K_NEW_RX_DESC_STATUS0_MORE;
- desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
- AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
- desc->ds_us.rx.rs_status = 0;
+ rs->rs_datalen = rx_status->rx_status_0 &
+ AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
+ rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+ AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+ rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+ AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
+ rs->rs_antenna = rx_status->rx_status_0 &
+ AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA;
+ rs->rs_more = rx_status->rx_status_0 &
+ AR5K_5212_RX_DESC_STATUS0_MORE;
+ rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+ AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+ rs->rs_status = 0;
/*
* Key table status
*/
- if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID)
- desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
- AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX);
+ if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
+ rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+ AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
else
- desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
+ rs->rs_keyix = AR5K_RXKEYIX_INVALID;
/*
* Receive/descriptor errors
*/
if ((rx_status->rx_status_1 &
- AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
- if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR)
- desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC;
+ AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
+ if (rx_status->rx_status_1 &
+ AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
+ rs->rs_status |= AR5K_RXERR_CRC;
if (rx_status->rx_status_1 &
- AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) {
- desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY;
- desc->ds_us.rx.rs_phyerr =
- AR5K_REG_MS(rx_err->rx_error_1,
- AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
+ AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
+ rs->rs_status |= AR5K_RXERR_PHY;
+ rs->rs_phyerr = AR5K_REG_MS(rx_err->rx_error_1,
+ AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
}
if (rx_status->rx_status_1 &
- AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
- desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT;
+ AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+ rs->rs_status |= AR5K_RXERR_DECRYPT;
- if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR)
- desc->ds_us.rx.rs_status |= AR5K_RXERR_MIC;
+ if (rx_status->rx_status_1 &
+ AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
+ rs->rs_status |= AR5K_RXERR_MIC;
}
return 0;
}
-/*********************************\
- Regulatory Domain/Channels Setup
-\*********************************/
-
-u16 ath5k_get_regdomain(struct ath5k_hw *ah)
-{
- u16 regdomain;
- enum ath5k_regdom ieee_regdomain;
-#ifdef COUNTRYCODE
- u16 code;
-#endif
-
- ath5k_eeprom_regulation_domain(ah, false, &ieee_regdomain);
- ah->ah_capabilities.cap_regdomain.reg_hw = ieee_regdomain;
-
-#ifdef COUNTRYCODE
- /*
- * Get the regulation domain by country code. This will ignore
- * the settings found in the EEPROM.
- */
- code = ieee80211_name2countrycode(COUNTRYCODE);
- ieee_regdomain = ieee80211_countrycode2regdomain(code);
-#endif
-
- regdomain = ath5k_regdom_from_ieee(ieee_regdomain);
- ah->ah_capabilities.cap_regdomain.reg_current = regdomain;
-
- return regdomain;
-}
/****************\
* (rX: reserved fields possibily used by future versions of the ar5k chipset)
*/
-struct ath5k_rx_desc {
+/*
+ * common hardware RX control descriptor
+ */
+struct ath5k_hw_rx_ctl {
u32 rx_control_0; /* RX control word 0 */
#define AR5K_DESC_RX_CTL0 0x00000000
} __packed;
/*
- * 5210/5211 rx status descriptor
+ * common hardware RX status descriptor
+ * 5210/11 and 5212 differ only in the flags defined below
*/
-struct ath5k_hw_old_rx_status {
+struct ath5k_hw_rx_status {
u32 rx_status_0; /* RX status word 0 */
-
-#define AR5K_OLD_RX_DESC_STATUS0_DATA_LEN 0x00000fff
-#define AR5K_OLD_RX_DESC_STATUS0_MORE 0x00001000
-#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000
-#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE_S 15
-#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000
-#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19
-#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000
-#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27
-
u32 rx_status_1; /* RX status word 1 */
-
-#define AR5K_OLD_RX_DESC_STATUS1_DONE 0x00000001
-#define AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
-#define AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR 0x00000004
-#define AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008
-#define AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010
-#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR 0x000000e0
-#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR_S 5
-#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100
-#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX 0x00007e00
-#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_S 9
-#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000
-#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15
-#define AR5K_OLD_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000
} __packed;
+/* 5210/5211 */
+#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff
+#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27
+#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001
+#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
+#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004
+#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008
+#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15
+#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000
+
+/* 5212 */
+#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff
+#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000
+#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28
+#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001
+#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
+#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004
+#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010
+#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16
+#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000
+
/*
- * 5212 rx status descriptor
+ * common hardware RX error descriptor
*/
-struct ath5k_hw_new_rx_status {
- u32 rx_status_0; /* RX status word 0 */
-
-#define AR5K_NEW_RX_DESC_STATUS0_DATA_LEN 0x00000fff
-#define AR5K_NEW_RX_DESC_STATUS0_MORE 0x00001000
-#define AR5K_NEW_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000
-#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000
-#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE_S 15
-#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000
-#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20
-#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000
-#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28
-
- u32 rx_status_1; /* RX status word 1 */
-
-#define AR5K_NEW_RX_DESC_STATUS1_DONE 0x00000001
-#define AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
-#define AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR 0x00000004
-#define AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008
-#define AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR 0x00000010
-#define AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR 0x00000020
-#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100
-#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00
-#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_S 9
-#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000
-#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16
-#define AR5K_NEW_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000
-} __packed;
-
struct ath5k_hw_rx_error {
u32 rx_error_0; /* RX error word 0 */
#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0
#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0
-struct ath5k_hw_2w_tx_desc {
+/*
+ * 5210/5211 hardware 2-word TX control descriptor
+ */
+struct ath5k_hw_2w_tx_ctl {
u32 tx_control_0; /* TX control word 0 */
#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff
#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10
/*
- * 5212 4-word tx control descriptor
+ * 5212 hardware 4-word TX control descriptor
*/
-struct ath5k_hw_4w_tx_desc {
+struct ath5k_hw_4w_tx_ctl {
u32 tx_control_0; /* TX control word 0 */
#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff
} __packed;
/*
- * Common tx status descriptor
+ * Common TX status descriptor
*/
struct ath5k_hw_tx_status {
u32 tx_status_0; /* TX status word 0 */
/*
+ * 5210/5211 hardware TX descriptor
+ */
+struct ath5k_hw_5210_tx_desc {
+ struct ath5k_hw_2w_tx_ctl tx_ctl;
+ struct ath5k_hw_tx_status tx_stat;
+} __packed;
+
+/*
+ * 5212 hardware TX descriptor
+ */
+struct ath5k_hw_5212_tx_desc {
+ struct ath5k_hw_4w_tx_ctl tx_ctl;
+ struct ath5k_hw_tx_status tx_stat;
+} __packed;
+
+/*
+ * common hardware RX descriptor
+ */
+struct ath5k_hw_all_rx_desc {
+ struct ath5k_hw_rx_ctl rx_ctl;
+ union {
+ struct ath5k_hw_rx_status rx_stat;
+ struct ath5k_hw_rx_error rx_err;
+ } u;
+} __packed;
+
+
+/*
* AR5K REGISTER ACCESS
*/
{ AR5K_PHY(644), 0x00806333 },
{ AR5K_PHY(645), 0x00106c10 },
{ AR5K_PHY(646), 0x009c4060 },
- /*{ AR5K_PHY(647), 0x1483800a },*/ /* Old value */
{ AR5K_PHY(647), 0x1483800a },
+ /* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413 */
{ AR5K_PHY(648), 0x01831061 },
{ AR5K_PHY(649), 0x00000400 },
/*{ AR5K_PHY(650), 0x000001b5 },*/
{ 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
};
+/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */
+/* XXX: No dumps for turbog yet, so turbog is the same with g here with some
+ * minor tweaking based on dumps from other chips */
+static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
+ { AR5K_TXCFG,
+ /* b g gTurbo */
+ { 0x00000015, 0x00000015, 0x00000015 } },
+ { AR5K_USEC_5211,
+ { 0x04e01395, 0x12e013ab, 0x098813cf } },
+ { AR5K_PHY(10),
+ { 0x05020000, 0x0a020001, 0x0a020001 } },
+ { AR5K_PHY(13),
+ { 0x00000e00, 0x00000e00, 0x00000e00 } },
+ { AR5K_PHY(14),
+ { 0x0000000a, 0x0000000a, 0x0000000a } },
+ { AR5K_PHY(18),
+ { 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
+ { AR5K_PHY(20),
+ { 0x0de8b0da, 0x0c98b0da, 0x0c98b0da } },
+ { AR5K_PHY_SIG,
+ { 0x7ee80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+ { AR5K_PHY_AGCCOARSE,
+ { 0x3137665e, 0x3139605e, 0x3139605e } },
+ { AR5K_PHY(27),
+ { 0x050cb081, 0x050cb081, 0x050cb081 } },
+ { AR5K_PHY_RX_DELAY,
+ { 0x0000044c, 0x00000898, 0x000007d0 } },
+ { AR5K_PHY_FRAME_CTL_5211,
+ { 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+ { AR5K_PHY_CCKTXCTL,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { AR5K_PHY(642),
+ { 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+ { AR5K_PHY_GAIN_2GHZ,
+ { 0x0042c140, 0x0042c140, 0x0042c140 } },
+ { 0xa21c,
+ { 0x1863800a, 0x1883800a, 0x1883800a } },
+ { AR5K_DCU_FP,
+ { 0x000003e0, 0x000003e0, 0x000003e0 } },
+ { 0x8060,
+ { 0x0000000f, 0x0000000f, 0x0000000f } },
+ { 0x8118,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x811c,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x8120,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x8124,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x8128,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x812c,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x8130,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x8134,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x8138,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x813c,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x8140,
+ { 0x800000a8, 0x800000a8, 0x800000a8 } },
+ { 0x8144,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { AR5K_PHY_AGC,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { AR5K_PHY(11),
+ { 0x0000a000, 0x0000a000, 0x0000a000 } },
+ { AR5K_PHY(15),
+ { 0x00200400, 0x00200400, 0x00200400 } },
+ { AR5K_PHY(19),
+ { 0x1284233c, 0x1284233c, 0x1284233c } },
+ { AR5K_PHY_SCR,
+ { 0x0000001f, 0x0000001f, 0x0000001f } },
+ { AR5K_PHY_SLMT,
+ { 0x00000080, 0x00000080, 0x00000080 } },
+ { AR5K_PHY_SCAL,
+ { 0x0000000e, 0x0000000e, 0x0000000e } },
+ { AR5K_PHY(86),
+ { 0x000000ff, 0x000000ff, 0x000000ff } },
+ { AR5K_PHY(96),
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { AR5K_PHY(97),
+ { 0x02800000, 0x02800000, 0x02800000 } },
+ { AR5K_PHY(104),
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { AR5K_PHY(120),
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { AR5K_PHY(121),
+ { 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } },
+ { AR5K_PHY(122),
+ { 0x3c466478, 0x3c466478, 0x3c466478 } },
+ { AR5K_PHY(123),
+ { 0x000000aa, 0x000000aa, 0x000000aa } },
+ { AR5K_PHY_SCLOCK,
+ { 0x0000000c, 0x0000000c, 0x0000000c } },
+ { AR5K_PHY_SDELAY,
+ { 0x000000ff, 0x000000ff, 0x000000ff } },
+ { AR5K_PHY_SPENDING,
+ { 0x00000014, 0x00000014, 0x00000014 } },
+ { 0xa228,
+ { 0x000009b5, 0x000009b5, 0x000009b5 } },
+ { 0xa23c,
+ { 0x93c889af, 0x93c889af, 0x93c889af } },
+ { 0xa24c,
+ { 0x00000001, 0x00000001, 0x00000001 } },
+ { 0xa250,
+ { 0x0000a000, 0x0000a000, 0x0000a000 } },
+ { 0xa254,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0xa258,
+ { 0x0cc75380, 0x0cc75380, 0x0cc75380 } },
+ { 0xa25c,
+ { 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } },
+ { 0xa260,
+ { 0x5f690f01, 0x5f690f01, 0x5f690f01 } },
+ { 0xa264,
+ { 0x00418a11, 0x00418a11, 0x00418a11 } },
+ { 0xa268,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0xa26c,
+ { 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } },
+ { 0xa270,
+ { 0x00820820, 0x00820820, 0x00820820 } },
+ { 0xa274,
+ { 0x001b7caa, 0x001b7caa, 0x001b7caa } },
+ { 0xa278,
+ { 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } },
+ { 0xa27c,
+ { 0x051701ce, 0x051701ce, 0x051701ce } },
+ { 0xa300,
+ { 0x18010000, 0x18010000, 0x18010000 } },
+ { 0xa304,
+ { 0x30032602, 0x30032602, 0x30032602 } },
+ { 0xa308,
+ { 0x48073e06, 0x48073e06, 0x48073e06 } },
+ { 0xa30c,
+ { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
+ { 0xa310,
+ { 0x641a600f, 0x641a600f, 0x641a600f } },
+ { 0xa314,
+ { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
+ { 0xa318,
+ { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
+ { 0xa31c,
+ { 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
+ { 0xa320,
+ { 0x9d4f970f, 0x9d4f970f, 0x9d4f970f } },
+ { 0xa324,
+ { 0xa5cfa18f, 0xa5cfa18f, 0xa5cfa18f } },
+ { 0xa328,
+ { 0xb55faf1f, 0xb55faf1f, 0xb55faf1f } },
+ { 0xa32c,
+ { 0xbddfb99f, 0xbddfb99f, 0xbddfb99f } },
+ { 0xa330,
+ { 0xcd7fc73f, 0xcd7fc73f, 0xcd7fc73f } },
+ { 0xa334,
+ { 0xd5ffd1bf, 0xd5ffd1bf, 0xd5ffd1bf } },
+ { 0xa338,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0xa33c,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0xa340,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0xa344,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0xa348,
+ { 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+ { 0xa34c,
+ { 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+ { 0xa350,
+ { 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+ { 0xa354,
+ { 0x0003ffff, 0x0003ffff, 0x0003ffff } },
+ { 0xa358,
+ { 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } },
+ { 0xa35c,
+ { 0x066c420f, 0x066c420f, 0x066c420f } },
+ { 0xa360,
+ { 0x0f282207, 0x0f282207, 0x0f282207 } },
+ { 0xa364,
+ { 0x17601685, 0x17601685, 0x17601685 } },
+ { 0xa368,
+ { 0x1f801104, 0x1f801104, 0x1f801104 } },
+ { 0xa36c,
+ { 0x37a00c03, 0x37a00c03, 0x37a00c03 } },
+ { 0xa370,
+ { 0x3fc40883, 0x3fc40883, 0x3fc40883 } },
+ { 0xa374,
+ { 0x57c00803, 0x57c00803, 0x57c00803 } },
+ { 0xa378,
+ { 0x5fd80682, 0x5fd80682, 0x5fd80682 } },
+ { 0xa37c,
+ { 0x7fe00482, 0x7fe00482, 0x7fe00482 } },
+ { 0xa380,
+ { 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } },
+ { 0xa384,
+ { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
+};
+
/*
* Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with
* RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI)
/* Second set of mode-specific settings */
if (ah->ah_radio == AR5K_RF5111){
+
ath5k_hw_ini_mode_registers(ah,
ARRAY_SIZE(ar5212_rf5111_ini_mode_end),
ar5212_rf5111_ini_mode_end, mode);
+
/* Baseband gain table */
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5111_ini_bbgain),
rf5111_ini_bbgain, change_channel);
+
} else if (ah->ah_radio == AR5K_RF5112){
+
ath5k_hw_ini_mode_registers(ah,
ARRAY_SIZE(ar5212_rf5112_ini_mode_end),
ar5212_rf5112_ini_mode_end, mode);
- /* Baseband gain table */
+
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5112_ini_bbgain),
rf5112_ini_bbgain, change_channel);
+
} else if (ah->ah_radio == AR5K_RF5413){
+
ath5k_hw_ini_mode_registers(ah,
ARRAY_SIZE(rf5413_ini_mode_end),
rf5413_ini_mode_end, mode);
+
+ ath5k_hw_ini_registers(ah,
+ ARRAY_SIZE(rf5112_ini_bbgain),
+ rf5112_ini_bbgain, change_channel);
+
+ } else if (ah->ah_radio == AR5K_RF2413) {
+
+ if (mode < 2) {
+ ATH5K_ERR(ah->ah_sc,
+ "unsupported channel mode: %d\n", mode);
+ return -EINVAL;
+ }
+ mode = mode - 2;
+
+ /* Override a setting from ar5212_ini */
+ ath5k_hw_reg_write(ah, 0x018830c6, AR5K_PHY(648));
+
+ ath5k_hw_ini_mode_registers(ah,
+ ARRAY_SIZE(rf2413_ini_mode_end),
+ rf2413_ini_mode_end, mode);
+
/* Baseband gain table */
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5112_ini_bbgain),
rf5112_ini_bbgain, change_channel);
+
}
/* For AR5211 */
} else if (ah->ah_version == AR5K_AR5211) {
- if(mode > 2){ /* AR5K_INI_VAL_11B */
- ATH5K_ERR(ah->ah_sc,"unsupported channel mode: %d\n", mode);
+ /* AR5K_MODE_11B */
+ if (mode > 2) {
+ ATH5K_ERR(ah->ah_sc,
+ "unsupported channel mode: %d\n", mode);
return -EINVAL;
}
{ 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
};
+/* RF2413/2414 mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_2413[] = {
+ { 1, AR5K_RF_BUFFER_CONTROL_4,
+ { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, AR5K_RF_BUFFER_CONTROL_3,
+ { 0x02001408, 0x02001408, 0x02001408 } },
+ { 3, AR5K_RF_BUFFER_CONTROL_6,
+ { 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0xf0000000, 0xf0000000, 0xf0000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x03000000, 0x03000000, 0x03000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x40400000, 0x40400000, 0x40400000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x65050000, 0x65050000, 0x65050000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00420000, 0x00420000, 0x00420000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00b50000, 0x00b50000, 0x00b50000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00030000, 0x00030000, 0x00030000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00f70000, 0x00f70000, 0x00f70000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x009d0000, 0x009d0000, 0x009d0000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00220000, 0x00220000, 0x00220000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x04220000, 0x04220000, 0x04220000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00230018, 0x00230018, 0x00230018 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00280050, 0x00280050, 0x00280050 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x005000c3, 0x005000c3, 0x005000c3 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x0004007f, 0x0004007f, 0x0004007f } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000458, 0x00000458, 0x00000458 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, AR5K_RF_BUFFER,
+ { 0x0000c000, 0x0000c000, 0x0000c000 } },
+ { 6, AR5K_RF_BUFFER_CONTROL_5,
+ { 0x00400230, 0x00400230, 0x00400230 } },
+ { 7, AR5K_RF_BUFFER,
+ { 0x00006400, 0x00006400, 0x00006400 } },
+ { 7, AR5K_RF_BUFFER,
+ { 0x00000800, 0x00000800, 0x00000800 } },
+ { 7, AR5K_RF_BUFFER_CONTROL_2,
+ { 0x0000000e, 0x0000000e, 0x0000000e } },
+};
/* Initial RF Gain settings for RF5112 */
static const struct ath5k_ini_rfgain rfgain_5112[] = {
{ AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } },
};
+/* Initial RF Gain settings for RF2413 */
+static const struct ath5k_ini_rfgain rfgain_2413[] = {
+ { AR5K_RF_GAIN(0), { 0x00000000 } },
+ { AR5K_RF_GAIN(1), { 0x00000040 } },
+ { AR5K_RF_GAIN(2), { 0x00000080 } },
+ { AR5K_RF_GAIN(3), { 0x00000181 } },
+ { AR5K_RF_GAIN(4), { 0x000001c1 } },
+ { AR5K_RF_GAIN(5), { 0x00000001 } },
+ { AR5K_RF_GAIN(6), { 0x00000041 } },
+ { AR5K_RF_GAIN(7), { 0x00000081 } },
+ { AR5K_RF_GAIN(8), { 0x00000168 } },
+ { AR5K_RF_GAIN(9), { 0x000001a8 } },
+ { AR5K_RF_GAIN(10), { 0x000001e8 } },
+ { AR5K_RF_GAIN(11), { 0x00000028 } },
+ { AR5K_RF_GAIN(12), { 0x00000068 } },
+ { AR5K_RF_GAIN(13), { 0x00000189 } },
+ { AR5K_RF_GAIN(14), { 0x000001c9 } },
+ { AR5K_RF_GAIN(15), { 0x00000009 } },
+ { AR5K_RF_GAIN(16), { 0x00000049 } },
+ { AR5K_RF_GAIN(17), { 0x00000089 } },
+ { AR5K_RF_GAIN(18), { 0x00000190 } },
+ { AR5K_RF_GAIN(19), { 0x000001d0 } },
+ { AR5K_RF_GAIN(20), { 0x00000010 } },
+ { AR5K_RF_GAIN(21), { 0x00000050 } },
+ { AR5K_RF_GAIN(22), { 0x00000090 } },
+ { AR5K_RF_GAIN(23), { 0x00000191 } },
+ { AR5K_RF_GAIN(24), { 0x000001d1 } },
+ { AR5K_RF_GAIN(25), { 0x00000011 } },
+ { AR5K_RF_GAIN(26), { 0x00000051 } },
+ { AR5K_RF_GAIN(27), { 0x00000091 } },
+ { AR5K_RF_GAIN(28), { 0x00000178 } },
+ { AR5K_RF_GAIN(29), { 0x000001b8 } },
+ { AR5K_RF_GAIN(30), { 0x000001f8 } },
+ { AR5K_RF_GAIN(31), { 0x00000038 } },
+ { AR5K_RF_GAIN(32), { 0x00000078 } },
+ { AR5K_RF_GAIN(33), { 0x00000199 } },
+ { AR5K_RF_GAIN(34), { 0x000001d9 } },
+ { AR5K_RF_GAIN(35), { 0x00000019 } },
+ { AR5K_RF_GAIN(36), { 0x00000059 } },
+ { AR5K_RF_GAIN(37), { 0x00000099 } },
+ { AR5K_RF_GAIN(38), { 0x000000d9 } },
+ { AR5K_RF_GAIN(39), { 0x000000f9 } },
+ { AR5K_RF_GAIN(40), { 0x000000f9 } },
+ { AR5K_RF_GAIN(41), { 0x000000f9 } },
+ { AR5K_RF_GAIN(42), { 0x000000f9 } },
+ { AR5K_RF_GAIN(43), { 0x000000f9 } },
+ { AR5K_RF_GAIN(44), { 0x000000f9 } },
+ { AR5K_RF_GAIN(45), { 0x000000f9 } },
+ { AR5K_RF_GAIN(46), { 0x000000f9 } },
+ { AR5K_RF_GAIN(47), { 0x000000f9 } },
+ { AR5K_RF_GAIN(48), { 0x000000f9 } },
+ { AR5K_RF_GAIN(49), { 0x000000f9 } },
+ { AR5K_RF_GAIN(50), { 0x000000f9 } },
+ { AR5K_RF_GAIN(51), { 0x000000f9 } },
+ { AR5K_RF_GAIN(52), { 0x000000f9 } },
+ { AR5K_RF_GAIN(53), { 0x000000f9 } },
+ { AR5K_RF_GAIN(54), { 0x000000f9 } },
+ { AR5K_RF_GAIN(55), { 0x000000f9 } },
+ { AR5K_RF_GAIN(56), { 0x000000f9 } },
+ { AR5K_RF_GAIN(57), { 0x000000f9 } },
+ { AR5K_RF_GAIN(58), { 0x000000f9 } },
+ { AR5K_RF_GAIN(59), { 0x000000f9 } },
+ { AR5K_RF_GAIN(60), { 0x000000f9 } },
+ { AR5K_RF_GAIN(61), { 0x000000f9 } },
+ { AR5K_RF_GAIN(62), { 0x000000f9 } },
+ { AR5K_RF_GAIN(63), { 0x000000f9 } },
+};
+
static const struct ath5k_gain_opt rfgain_opt_5112 = {
1,
8,
entry = ((first - 1) / 8) + offset;
position = (first - 1) % 8;
- if (set == true)
+ if (set)
data = ath5k_hw_bitswap(reg, bits);
for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) {
last = (position + left > 8) ? 8 : position + left;
mask = (((1 << last) - 1) ^ ((1 << position) - 1)) << (col * 8);
- if (set == true) {
+ if (set) {
rf[entry] &= ~mask;
rf[entry] |= ((data << position) << (col * 8)) & mask;
data >>= (8 - position);
left -= 8 - position;
}
- data = set == true ? 1 : ath5k_hw_bitswap(data, bits);
+ data = set ? 1 : ath5k_hw_bitswap(data, bits);
return data;
}
go = &rfgain_opt_5111;
break;
case AR5K_RF5112:
- case AR5K_RF5413: /* ??? */
go = &rfgain_opt_5112;
break;
default:
int obdb = -1, bank = -1;
u32 ee_mode;
- AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+ AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX);
rf = ah->ah_rf_banks;
}
/* Modify bank 0 */
- if (channel->val & CHANNEL_2GHZ) {
- if (channel->val & CHANNEL_CCK)
+ if (channel->hw_value & CHANNEL_2GHZ) {
+ if (channel->hw_value & CHANNEL_CCK)
ee_mode = AR5K_EEPROM_MODE_11B;
else
ee_mode = AR5K_EEPROM_MODE_11G;
} else {
/* For 11a, Turbo and XR */
ee_mode = AR5K_EEPROM_MODE_11A;
- obdb = channel->freq >= 5725 ? 3 :
- (channel->freq >= 5500 ? 2 :
- (channel->freq >= 5260 ? 1 :
- (channel->freq > 4000 ? 0 : -1)));
+ obdb = channel->center_freq >= 5725 ? 3 :
+ (channel->center_freq >= 5500 ? 2 :
+ (channel->center_freq >= 5260 ? 1 :
+ (channel->center_freq > 4000 ? 0 : -1)));
if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
ee->ee_pwd_84, 1, 51, 3, true))
int obdb = -1, bank = -1;
u32 ee_mode;
- AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+ AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX);
rf = ah->ah_rf_banks;
if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_2112A
- && !test_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode)){
+ && !test_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode)) {
rf_ini = rfregs_2112a;
rf_size = ARRAY_SIZE(rfregs_5112a);
if (mode < 2) {
}
/* Modify bank 6 */
- if (channel->val & CHANNEL_2GHZ) {
- if (channel->val & CHANNEL_OFDM)
+ if (channel->hw_value & CHANNEL_2GHZ) {
+ if (channel->hw_value & CHANNEL_OFDM)
ee_mode = AR5K_EEPROM_MODE_11G;
else
ee_mode = AR5K_EEPROM_MODE_11B;
} else {
/* For 11a, Turbo and XR */
ee_mode = AR5K_EEPROM_MODE_11A;
- obdb = channel->freq >= 5725 ? 3 :
- (channel->freq >= 5500 ? 2 :
- (channel->freq >= 5260 ? 1 :
- (channel->freq > 4000 ? 0 : -1)));
+ obdb = channel->center_freq >= 5725 ? 3 :
+ (channel->center_freq >= 5500 ? 2 :
+ (channel->center_freq >= 5260 ? 1 :
+ (channel->center_freq > 4000 ? 0 : -1)));
+
+ if (obdb == -1)
+ return -EINVAL;
if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
ee->ee_ob[ee_mode][obdb], 3, 279, 0, true))
unsigned int rf_size, i;
int bank = -1;
- AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+ AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX);
rf = ah->ah_rf_banks;
- rf_ini = rfregs_5413;
- rf_size = ARRAY_SIZE(rfregs_5413);
+ if (ah->ah_radio == AR5K_RF5413) {
+ rf_ini = rfregs_5413;
+ rf_size = ARRAY_SIZE(rfregs_5413);
+ } else if (ah->ah_radio == AR5K_RF2413) {
+ rf_ini = rfregs_2413;
+ rf_size = ARRAY_SIZE(rfregs_2413);
+ if (mode < 2) {
+ ATH5K_ERR(ah->ah_sc,
+ "invalid channel mode: %i\n", mode);
+ return -EINVAL;
+ }
+ mode = mode - 2;
+ } else {
+ return -EINVAL;
+ }
/* Copy values to modify them */
for (i = 0; i < rf_size; i++) {
ah->ah_rf_banks_size = sizeof(rfregs_5413);
func = ath5k_hw_rf5413_rfregs;
break;
+ case AR5K_RF2413:
+ ah->ah_rf_banks_size = sizeof(rfregs_2413);
+ func = ath5k_hw_rf5413_rfregs;
+ break;
default:
return -EINVAL;
}
ath5k_rfg = rfgain_5413;
size = ARRAY_SIZE(rfgain_5413);
break;
+ case AR5K_RF2413:
+ ath5k_rfg = rfgain_2413;
+ size = ARRAY_SIZE(rfgain_2413);
+ freq = 0; /* only 2Ghz */
+ break;
default:
return -EINVAL;
}
ah->ah_gain.g_active = 1;
break;
case AR5K_RF5112:
- case AR5K_RF5413: /* ??? */
ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
ah->ah_gain.g_step =
&rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx];
* newer chipsets like the AR5212A who have a completely
* different RF/PHY part.
*/
- athchan = (ath5k_hw_bitswap((channel->chan - 24) / 2, 5) << 1) |
- (1 << 6) | 0x1;
-
+ athchan = (ath5k_hw_bitswap(
+ (ieee80211_frequency_to_channel(
+ channel->center_freq) - 24) / 2, 5)
+ << 1) | (1 << 6) | 0x1;
return athchan;
}
struct ieee80211_channel *channel)
{
struct ath5k_athchan_2ghz ath5k_channel_2ghz;
- unsigned int ath5k_channel = channel->chan;
+ unsigned int ath5k_channel =
+ ieee80211_frequency_to_channel(channel->center_freq);
u32 data0, data1, clock;
int ret;
*/
data0 = data1 = 0;
- if (channel->val & CHANNEL_2GHZ) {
+ if (channel->hw_value & CHANNEL_2GHZ) {
/* Map 2GHz channel to 5GHz Atheros channel ID */
- ret = ath5k_hw_rf5111_chan2athchan(channel->chan,
- &ath5k_channel_2ghz);
+ ret = ath5k_hw_rf5111_chan2athchan(
+ ieee80211_frequency_to_channel(channel->center_freq),
+ &ath5k_channel_2ghz);
if (ret)
return ret;
u16 c;
data = data0 = data1 = data2 = 0;
- c = channel->freq;
+ c = channel->center_freq;
/*
* Set the channel on the RF5112 or newer
int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
{
int ret;
-
/*
- * Check bounds supported by the PHY
- * (don't care about regulation restrictions at this point)
- */
- if ((channel->freq < ah->ah_capabilities.cap_range.range_2ghz_min ||
- channel->freq > ah->ah_capabilities.cap_range.range_2ghz_max) &&
- (channel->freq < ah->ah_capabilities.cap_range.range_5ghz_min ||
- channel->freq > ah->ah_capabilities.cap_range.range_5ghz_max)) {
+ * Check bounds supported by the PHY (we don't care about regultory
+ * restrictions at this point). Note: hw_value already has the band
+ * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
+ * of the band by that */
+ if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
ATH5K_ERR(ah->ah_sc,
- "channel out of supported range (%u MHz)\n",
- channel->freq);
- return -EINVAL;
+ "channel frequency (%u MHz) out of supported "
+ "band range\n",
+ channel->center_freq);
+ return -EINVAL;
}
/*
if (ret)
return ret;
- ah->ah_current_channel.freq = channel->freq;
- ah->ah_current_channel.val = channel->val;
- ah->ah_turbo = channel->val == CHANNEL_T ? true : false;
+ ah->ah_current_channel.center_freq = channel->center_freq;
+ ah->ah_current_channel.hw_value = channel->hw_value;
+ ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
return 0;
}
if (ret) {
ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
- channel->freq);
+ channel->center_freq);
return ret;
}
- ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
+ ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
if (ret)
return ret;
s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
ATH5K_TRACE(ah->ah_sc);
- if (ah->ah_calibration == false ||
+ if (!ah->ah_calibration ||
ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
goto done;
((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
done:
- ath5k_hw_noise_floor_calibration(ah, channel->freq);
+ ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
/* Request RF gain */
- if (channel->val & CHANNEL_5GHZ) {
+ if (channel->hw_value & CHANNEL_5GHZ) {
ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
AR5K_PHY_PAPD_PROBE_TXPOWER) |
AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
return -EINVAL;
}
+ /*
+ * RF2413 for some reason can't
+ * transmit anything if we call
+ * this funtion, so we skip it
+ * until we fix txpower.
+ */
+ if (ah->ah_radio == AR5K_RF2413)
+ return 0;
+
/* Reset TX power values */
memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
ah->ah_txpower.txp_tpc = tpc;
AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
- if (ah->ah_txpower.txp_tpc == true)
+ if (ah->ah_txpower.txp_tpc)
ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
else
#define AR5K_PHY_SDELAY_32MHZ 0x000000ff
#define AR5K_PHY_SPENDING 0x99f8
#define AR5K_PHY_SPENDING_RF5111 0x00000018
-#define AR5K_PHY_SPENDING_RF5112 0x00000014
+#define AR5K_PHY_SPENDING_RF5112 0x00000014 /* <- i 've only seen this on 2425 dumps ! */
+#define AR5K_PHY_SPENDING_RF5112A 0x0000000e /* but since i only have 5112A-based chips */
+#define AR5K_PHY_SPENDING_RF5424 0x00000012 /* to test it might be also for old 5112. */
/*
* Misc PHY/radio registers [5110 - 5111]
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
+#include <linux/jiffies.h>
#include <net/ieee80211.h>
#include "atmel.h"
SITE_SURVEY_IN_PROGRESS,
SITE_SURVEY_COMPLETED
} site_survey_state;
- time_t last_survey;
+ unsigned long last_survey;
int station_was_associated, station_is_associated;
int fast_scan;
return -EAGAIN;
/* Timeout old surveys. */
- if ((jiffies - priv->last_survey) > (20 * HZ))
+ if (time_after(jiffies, priv->last_survey + 20 * HZ))
priv->site_survey_state = SITE_SURVEY_IDLE;
priv->last_survey = jiffies;
#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
#define B43_MMIO_RNG 0x65A
+#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */
+#define B43_MMIO_IFSCTL_USE_EDCF 0x0004
#define B43_MMIO_POWERUP_DELAY 0x6A8
/* SPROM boardflags_lo values */
#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */
#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
-#define B43_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */
+#define B43_SHM_SH_HOSTFMI 0x0060 /* Hostflags for ucode options (middle) */
+#define B43_SHM_SH_HOSTFHI 0x0062 /* Hostflags for ucode options (high) */
#define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */
#define B43_SHM_SH_RADAR 0x0066 /* Radar register */
#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
#define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
/* HostFlags. See b43_hf_read/write() */
-#define B43_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */
-#define B43_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
-#define B43_HF_RXPULLW 0x00000004 /* RX pullup workaround */
-#define B43_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */
-#define B43_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */
-#define B43_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */
-#define B43_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */
-#define B43_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */
-#define B43_HF_EDCF 0x00000100 /* on if WME and MAC suspended */
-#define B43_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */
-#define B43_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */
-#define B43_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */
-#define B43_HF_2060W 0x00001000 /* 2060 radio workaround */
-#define B43_HF_RADARW 0x00002000 /* Radar workaround */
-#define B43_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */
-#define B43_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */
-#define B43_HF_FWKUP 0x00020000 /* Fast wake-up ucode */
-#define B43_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */
-#define B43_HF_PCISCW 0x00080000 /* PCI slow clock workaround */
-#define B43_HF_4318TSSI 0x00200000 /* 4318 TSSI */
-#define B43_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */
-#define B43_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */
-#define B43_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */
-#define B43_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */
-#define B43_HF_SKCFPUP 0x04000000 /* Skip CFP update */
+#define B43_HF_ANTDIVHELP 0x000000000001ULL /* ucode antenna div helper */
+#define B43_HF_SYMW 0x000000000002ULL /* G-PHY SYM workaround */
+#define B43_HF_RXPULLW 0x000000000004ULL /* RX pullup workaround */
+#define B43_HF_CCKBOOST 0x000000000008ULL /* 4dB CCK power boost (exclusive with OFDM boost) */
+#define B43_HF_BTCOEX 0x000000000010ULL /* Bluetooth coexistance */
+#define B43_HF_GDCW 0x000000000020ULL /* G-PHY DC canceller filter bw workaround */
+#define B43_HF_OFDMPABOOST 0x000000000040ULL /* Enable PA gain boost for OFDM */
+#define B43_HF_ACPR 0x000000000080ULL /* Disable for Japan, channel 14 */
+#define B43_HF_EDCF 0x000000000100ULL /* on if WME and MAC suspended */
+#define B43_HF_TSSIRPSMW 0x000000000200ULL /* TSSI reset PSM ucode workaround */
+#define B43_HF_20IN40IQW 0x000000000200ULL /* 20 in 40 MHz I/Q workaround (rev >= 13 only) */
+#define B43_HF_DSCRQ 0x000000000400ULL /* Disable slow clock request in ucode */
+#define B43_HF_ACIW 0x000000000800ULL /* ACI workaround: shift bits by 2 on PHY CRS */
+#define B43_HF_2060W 0x000000001000ULL /* 2060 radio workaround */
+#define B43_HF_RADARW 0x000000002000ULL /* Radar workaround */
+#define B43_HF_USEDEFKEYS 0x000000004000ULL /* Enable use of default keys */
+#define B43_HF_AFTERBURNER 0x000000008000ULL /* Afterburner enabled */
+#define B43_HF_BT4PRIOCOEX 0x000000010000ULL /* Bluetooth 4-priority coexistance */
+#define B43_HF_FWKUP 0x000000020000ULL /* Fast wake-up ucode */
+#define B43_HF_VCORECALC 0x000000040000ULL /* Force VCO recalculation when powering up synthpu */
+#define B43_HF_PCISCW 0x000000080000ULL /* PCI slow clock workaround */
+#define B43_HF_4318TSSI 0x000000200000ULL /* 4318 TSSI */
+#define B43_HF_FBCMCFIFO 0x000000400000ULL /* Flush bcast/mcast FIFO immediately */
+#define B43_HF_HWPCTL 0x000000800000ULL /* Enable hardwarre power control */
+#define B43_HF_BTCOEXALT 0x000001000000ULL /* Bluetooth coexistance in alternate pins */
+#define B43_HF_TXBTCHECK 0x000002000000ULL /* Bluetooth check during transmission */
+#define B43_HF_SKCFPUP 0x000004000000ULL /* Skip CFP update */
+#define B43_HF_N40W 0x000008000000ULL /* N PHY 40 MHz workaround (rev >= 13 only) */
+#define B43_HF_ANTSEL 0x000020000000ULL /* Antenna selection (for testing antenna div.) */
+#define B43_HF_BT3COEXT 0x000020000000ULL /* Bluetooth 3-wire coexistence (rev >= 13 only) */
+#define B43_HF_BTCANT 0x000040000000ULL /* Bluetooth coexistence (antenna mode) (rev >= 13 only) */
+#define B43_HF_ANTSELEN 0x000100000000ULL /* Antenna selection enabled (rev >= 13 only) */
+#define B43_HF_ANTSELMODE 0x000200000000ULL /* Antenna selection mode (rev >= 13 only) */
+#define B43_HF_MLADVW 0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */
+#define B43_HF_PR45960W 0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */
/* MacFilter offsets. */
#define B43_MACFILTER_SELF 0x0000
} __attribute__((__packed__));
-#define B43_PHYMODE(phytype) (1 << (phytype))
-#define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A)
-#define B43_PHYMODE_B B43_PHYMODE(B43_PHYTYPE_B)
-#define B43_PHYMODE_G B43_PHYMODE(B43_PHYTYPE_G)
-
struct b43_phy {
- /* Possible PHYMODEs on this PHY */
- u8 possible_phymodes;
+ /* Band support flags. */
+ bool supports_2ghz;
+ bool supports_5ghz;
+
/* GMODE bit enabled? */
bool gmode;
- /* Possible ieee80211 subsystem hwmodes for this PHY.
- * Which mode is selected, depends on thr GMODE enabled bit */
-#define B43_MAX_PHYHWMODES 2
- struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
/* Analog Type */
u8 analog;
/* Data structures for DMA transmission, per 80211 core. */
struct b43_dma {
- struct b43_dmaring *tx_ring0;
- struct b43_dmaring *tx_ring1;
- struct b43_dmaring *tx_ring2;
- struct b43_dmaring *tx_ring3;
- struct b43_dmaring *tx_ring4;
- struct b43_dmaring *tx_ring5;
-
- struct b43_dmaring *rx_ring0;
- struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */
+ struct b43_dmaring *tx_ring_AC_BK; /* Background */
+ struct b43_dmaring *tx_ring_AC_BE; /* Best Effort */
+ struct b43_dmaring *tx_ring_AC_VI; /* Video */
+ struct b43_dmaring *tx_ring_AC_VO; /* Voice */
+ struct b43_dmaring *tx_ring_mcast; /* Multicast */
+
+ struct b43_dmaring *rx_ring;
};
/* Context information for a noise calculation (Link Quality). */
u8 algorithm;
};
+/* SHM offsets to the QOS data structures for the 4 different queues. */
+#define B43_QOS_PARAMS(queue) (B43_SHM_SH_EDCFQ + \
+ (B43_NR_QOSPARAMS * sizeof(u16) * (queue)))
+#define B43_QOS_BACKGROUND B43_QOS_PARAMS(0)
+#define B43_QOS_BESTEFFORT B43_QOS_PARAMS(1)
+#define B43_QOS_VIDEO B43_QOS_PARAMS(2)
+#define B43_QOS_VOICE B43_QOS_PARAMS(3)
+
+/* QOS parameter hardware data structure offsets. */
+#define B43_NR_QOSPARAMS 22
+enum {
+ B43_QOSPARAM_TXOP = 0,
+ B43_QOSPARAM_CWMIN,
+ B43_QOSPARAM_CWMAX,
+ B43_QOSPARAM_CWCUR,
+ B43_QOSPARAM_AIFS,
+ B43_QOSPARAM_BSLOTS,
+ B43_QOSPARAM_REGGAP,
+ B43_QOSPARAM_STATUS,
+};
+
+/* QOS parameters for a queue. */
+struct b43_qos_params {
+ /* The QOS parameters */
+ struct ieee80211_tx_queue_params p;
+ /* Does this need to get uploaded to hardware? */
+ bool need_hw_update;
+};
+
struct b43_wldev;
/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
struct sk_buff *current_beacon;
bool beacon0_uploaded;
bool beacon1_uploaded;
+
+ /* The current QOS parameters for the 4 queues.
+ * This is protected by the irq_lock. */
+ struct b43_qos_params qos_params[4];
+ /* Workqueue for updating QOS parameters in hardware. */
+ struct work_struct qos_update_work;
};
/* In-memory representation of a cached microcode file. */
bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */
- bool short_preamble; /* TRUE, if short preamble is enabled. */
bool short_slot; /* TRUE, if short slot timing is enabled. */
bool radio_hw_enable; /* saved state of radio hardware enabled state */
bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
+#include <asm/div64.h>
/* 32bit DMA ops. */
return slot;
}
-/* Mac80211-queue to b43-ring mapping */
-static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
- int queue_priority)
-{
- struct b43_dmaring *ring;
-
-/*FIXME: For now we always run on TX-ring-1 */
- return dev->dma.tx_ring1;
-
- /* 0 = highest priority */
- switch (queue_priority) {
- default:
- B43_WARN_ON(1);
- /* fallthrough */
- case 0:
- ring = dev->dma.tx_ring3;
- break;
- case 1:
- ring = dev->dma.tx_ring2;
- break;
- case 2:
- ring = dev->dma.tx_ring1;
- break;
- case 3:
- ring = dev->dma.tx_ring0;
- break;
- }
-
- return ring;
-}
-
-/* b43-ring to mac80211-queue mapping */
-static inline int txring_to_priority(struct b43_dmaring *ring)
-{
- static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
- unsigned int index;
-
-/*FIXME: have only one queue, for now */
- return 0;
-
- index = ring->index;
- if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
- index = 0;
- return idx_to_prio[index];
-}
-
static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
{
static const u16 map64[] = {
goto out;
}
+#define divide(a, b) ({ \
+ typeof(a) __a = a; \
+ do_div(__a, b); \
+ __a; \
+ })
+
+#define modulo(a, b) ({ \
+ typeof(a) __a = a; \
+ do_div(__a, b); \
+ })
+
/* Main cleanup function. */
-static void b43_destroy_dmaring(struct b43_dmaring *ring)
+static void b43_destroy_dmaring(struct b43_dmaring *ring,
+ const char *ringname)
{
if (!ring)
return;
- b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
- (unsigned int)(ring->type),
- ring->mmio_base,
- (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
+#ifdef CONFIG_B43_DEBUG
+ {
+ /* Print some statistics. */
+ u64 failed_packets = ring->nr_failed_tx_packets;
+ u64 succeed_packets = ring->nr_succeed_tx_packets;
+ u64 nr_packets = failed_packets + succeed_packets;
+ u64 permille_failed = 0, average_tries = 0;
+
+ if (nr_packets)
+ permille_failed = divide(failed_packets * 1000, nr_packets);
+ if (nr_packets)
+ average_tries = divide(ring->nr_total_packet_tries * 100, nr_packets);
+
+ b43dbg(ring->dev->wl, "DMA-%u %s: "
+ "Used slots %d/%d, Failed frames %llu/%llu = %llu.%01llu%%, "
+ "Average tries %llu.%02llu\n",
+ (unsigned int)(ring->type), ringname,
+ ring->max_used_slots,
+ ring->nr_slots,
+ (unsigned long long)failed_packets,
+ (unsigned long long)nr_packets,
+ (unsigned long long)divide(permille_failed, 10),
+ (unsigned long long)modulo(permille_failed, 10),
+ (unsigned long long)divide(average_tries, 100),
+ (unsigned long long)modulo(average_tries, 100));
+ }
+#endif /* DEBUG */
+
/* Device IRQs are disabled prior entering this function,
* so no need to take care of concurrency with rx handler stuff.
*/
kfree(ring);
}
+#define destroy_ring(dma, ring) do { \
+ b43_destroy_dmaring((dma)->ring, __stringify(ring)); \
+ (dma)->ring = NULL; \
+ } while (0)
+
void b43_dma_free(struct b43_wldev *dev)
{
struct b43_dma *dma = &dev->dma;
- b43_destroy_dmaring(dma->rx_ring3);
- dma->rx_ring3 = NULL;
- b43_destroy_dmaring(dma->rx_ring0);
- dma->rx_ring0 = NULL;
-
- b43_destroy_dmaring(dma->tx_ring5);
- dma->tx_ring5 = NULL;
- b43_destroy_dmaring(dma->tx_ring4);
- dma->tx_ring4 = NULL;
- b43_destroy_dmaring(dma->tx_ring3);
- dma->tx_ring3 = NULL;
- b43_destroy_dmaring(dma->tx_ring2);
- dma->tx_ring2 = NULL;
- b43_destroy_dmaring(dma->tx_ring1);
- dma->tx_ring1 = NULL;
- b43_destroy_dmaring(dma->tx_ring0);
- dma->tx_ring0 = NULL;
+ destroy_ring(dma, rx_ring);
+ destroy_ring(dma, tx_ring_AC_BK);
+ destroy_ring(dma, tx_ring_AC_BE);
+ destroy_ring(dma, tx_ring_AC_VI);
+ destroy_ring(dma, tx_ring_AC_VO);
+ destroy_ring(dma, tx_ring_mcast);
}
int b43_dma_init(struct b43_wldev *dev)
{
struct b43_dma *dma = &dev->dma;
- struct b43_dmaring *ring;
int err;
u64 dmamask;
enum b43_dmatype type;
err = -ENOMEM;
/* setup TX DMA channels. */
- ring = b43_setup_dmaring(dev, 0, 1, type);
- if (!ring)
+ dma->tx_ring_AC_BK = b43_setup_dmaring(dev, 0, 1, type);
+ if (!dma->tx_ring_AC_BK)
goto out;
- dma->tx_ring0 = ring;
- ring = b43_setup_dmaring(dev, 1, 1, type);
- if (!ring)
- goto err_destroy_tx0;
- dma->tx_ring1 = ring;
+ dma->tx_ring_AC_BE = b43_setup_dmaring(dev, 1, 1, type);
+ if (!dma->tx_ring_AC_BE)
+ goto err_destroy_bk;
- ring = b43_setup_dmaring(dev, 2, 1, type);
- if (!ring)
- goto err_destroy_tx1;
- dma->tx_ring2 = ring;
+ dma->tx_ring_AC_VI = b43_setup_dmaring(dev, 2, 1, type);
+ if (!dma->tx_ring_AC_VI)
+ goto err_destroy_be;
- ring = b43_setup_dmaring(dev, 3, 1, type);
- if (!ring)
- goto err_destroy_tx2;
- dma->tx_ring3 = ring;
+ dma->tx_ring_AC_VO = b43_setup_dmaring(dev, 3, 1, type);
+ if (!dma->tx_ring_AC_VO)
+ goto err_destroy_vi;
- ring = b43_setup_dmaring(dev, 4, 1, type);
- if (!ring)
- goto err_destroy_tx3;
- dma->tx_ring4 = ring;
+ dma->tx_ring_mcast = b43_setup_dmaring(dev, 4, 1, type);
+ if (!dma->tx_ring_mcast)
+ goto err_destroy_vo;
- ring = b43_setup_dmaring(dev, 5, 1, type);
- if (!ring)
- goto err_destroy_tx4;
- dma->tx_ring5 = ring;
+ /* setup RX DMA channel. */
+ dma->rx_ring = b43_setup_dmaring(dev, 0, 0, type);
+ if (!dma->rx_ring)
+ goto err_destroy_mcast;
- /* setup RX DMA channels. */
- ring = b43_setup_dmaring(dev, 0, 0, type);
- if (!ring)
- goto err_destroy_tx5;
- dma->rx_ring0 = ring;
-
- if (dev->dev->id.revision < 5) {
- ring = b43_setup_dmaring(dev, 3, 0, type);
- if (!ring)
- goto err_destroy_rx0;
- dma->rx_ring3 = ring;
- }
+ /* No support for the TX status DMA ring. */
+ B43_WARN_ON(dev->dev->id.revision < 5);
b43dbg(dev->wl, "%u-bit DMA initialized\n",
(unsigned int)type);
err = 0;
- out:
+out:
return err;
- err_destroy_rx0:
- b43_destroy_dmaring(dma->rx_ring0);
- dma->rx_ring0 = NULL;
- err_destroy_tx5:
- b43_destroy_dmaring(dma->tx_ring5);
- dma->tx_ring5 = NULL;
- err_destroy_tx4:
- b43_destroy_dmaring(dma->tx_ring4);
- dma->tx_ring4 = NULL;
- err_destroy_tx3:
- b43_destroy_dmaring(dma->tx_ring3);
- dma->tx_ring3 = NULL;
- err_destroy_tx2:
- b43_destroy_dmaring(dma->tx_ring2);
- dma->tx_ring2 = NULL;
- err_destroy_tx1:
- b43_destroy_dmaring(dma->tx_ring1);
- dma->tx_ring1 = NULL;
- err_destroy_tx0:
- b43_destroy_dmaring(dma->tx_ring0);
- dma->tx_ring0 = NULL;
- goto out;
+err_destroy_mcast:
+ destroy_ring(dma, tx_ring_mcast);
+err_destroy_vo:
+ destroy_ring(dma, tx_ring_AC_VO);
+err_destroy_vi:
+ destroy_ring(dma, tx_ring_AC_VI);
+err_destroy_be:
+ destroy_ring(dma, tx_ring_AC_BE);
+err_destroy_bk:
+ destroy_ring(dma, tx_ring_AC_BK);
+ return err;
}
/* Generate a cookie for the TX header. */
static u16 generate_cookie(struct b43_dmaring *ring, int slot)
{
- u16 cookie = 0x1000;
+ u16 cookie;
/* Use the upper 4 bits of the cookie as
* DMA controller ID and store the slot number
* It can also not be 0xFFFF because that is special
* for multicast frames.
*/
- switch (ring->index) {
- case 0:
- cookie = 0x1000;
- break;
- case 1:
- cookie = 0x2000;
- break;
- case 2:
- cookie = 0x3000;
- break;
- case 3:
- cookie = 0x4000;
- break;
- case 4:
- cookie = 0x5000;
- break;
- case 5:
- cookie = 0x6000;
- break;
- default:
- B43_WARN_ON(1);
- }
+ cookie = (((u16)ring->index + 1) << 12);
B43_WARN_ON(slot & ~0x0FFF);
- cookie |= (u16) slot;
+ cookie |= (u16)slot;
return cookie;
}
switch (cookie & 0xF000) {
case 0x1000:
- ring = dma->tx_ring0;
+ ring = dma->tx_ring_AC_BK;
break;
case 0x2000:
- ring = dma->tx_ring1;
+ ring = dma->tx_ring_AC_BE;
break;
case 0x3000:
- ring = dma->tx_ring2;
+ ring = dma->tx_ring_AC_VI;
break;
case 0x4000:
- ring = dma->tx_ring3;
+ ring = dma->tx_ring_AC_VO;
break;
case 0x5000:
- ring = dma->tx_ring4;
- break;
- case 0x6000:
- ring = dma->tx_ring5;
+ ring = dma->tx_ring_mcast;
break;
default:
B43_WARN_ON(1);
return 0;
}
+/* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */
+static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev,
+ u8 queue_prio)
+{
+ struct b43_dmaring *ring;
+
+ if (b43_modparam_qos) {
+ /* 0 = highest priority */
+ switch (queue_prio) {
+ default:
+ B43_WARN_ON(1);
+ /* fallthrough */
+ case 0:
+ ring = dev->dma.tx_ring_AC_VO;
+ break;
+ case 1:
+ ring = dev->dma.tx_ring_AC_VI;
+ break;
+ case 2:
+ ring = dev->dma.tx_ring_AC_BE;
+ break;
+ case 3:
+ ring = dev->dma.tx_ring_AC_BK;
+ break;
+ }
+ } else
+ ring = dev->dma.tx_ring_AC_BE;
+
+ return ring;
+}
+
int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{
hdr = (struct ieee80211_hdr *)skb->data;
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
/* The multicast ring will be sent after the DTIM */
- ring = dev->dma.tx_ring4;
+ ring = dev->dma.tx_ring_mcast;
/* Set the more-data bit. Ucode will clear it on
* the last frame for us. */
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} else {
/* Decide by priority where to put this frame. */
- ring = priority_to_txring(dev, ctl->queue);
+ ring = select_ring_by_priority(dev, ctl->queue);
}
spin_lock_irqsave(&ring->lock, flags);
* That would be a mac80211 bug. */
B43_WARN_ON(ring->stopped);
+ /* Assign the queue number to the ring (if not already done before)
+ * so TX status handling can use it. The queue to ring mapping is
+ * static, so we don't need to store it per frame. */
+ ring->queue_prio = ctl->queue;
+
err = dma_tx_fragment(ring, skb, ctl);
if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key
if ((free_slots(ring) < SLOTS_PER_PACKET) ||
should_inject_overflow(ring)) {
/* This TX ring is full. */
- ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
+ ieee80211_stop_queue(dev->wl->hw, ctl->queue);
ring->stopped = 1;
if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
return err;
}
+static void b43_fill_txstatus_report(struct b43_dmaring *ring,
+ struct ieee80211_tx_status *report,
+ const struct b43_txstatus *status)
+{
+ bool frame_failed = 0;
+
+ if (status->acked) {
+ /* The frame was ACKed. */
+ report->flags |= IEEE80211_TX_STATUS_ACK;
+ } else {
+ /* The frame was not ACKed... */
+ if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ /* ...but we expected an ACK. */
+ frame_failed = 1;
+ report->excessive_retries = 1;
+ }
+ }
+ if (status->frame_count == 0) {
+ /* The frame was not transmitted at all. */
+ report->retry_count = 0;
+ } else {
+ report->retry_count = status->frame_count - 1;
+#ifdef CONFIG_B43_DEBUG
+ if (frame_failed)
+ ring->nr_failed_tx_packets++;
+ else
+ ring->nr_succeed_tx_packets++;
+ ring->nr_total_packet_tries += status->frame_count;
+#endif /* DEBUG */
+ }
+}
+
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
* status of the transmission.
* Some fields of txstat are already filled in dma_tx().
*/
- if (status->acked) {
- meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
- } else {
- if (!(meta->txstat.control.flags
- & IEEE80211_TXCTL_NO_ACK))
- meta->txstat.excessive_retries = 1;
- }
- if (status->frame_count == 0) {
- /* The frame was not transmitted at all. */
- meta->txstat.retry_count = 0;
- } else
- meta->txstat.retry_count = status->frame_count - 1;
+ b43_fill_txstatus_report(ring, &(meta->txstat), status);
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
&(meta->txstat));
/* skb is freed by ieee80211_tx_status_irqsafe() */
dev->stats.last_tx = jiffies;
if (ring->stopped) {
B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
- ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
+ ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
ring->stopped = 0;
if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
for (i = 0; i < nr_queues; i++) {
data = &(stats->data[i]);
- ring = priority_to_txring(dev, i);
+ ring = select_ring_by_priority(dev, i);
spin_lock_irqsave(&ring->lock, flags);
data->len = ring->used_slots / SLOTS_PER_PACKET;
sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
skb = meta->skb;
- if (ring->index == 3) {
- /* We received an xmit status. */
- struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data;
- int i = 0;
-
- while (hw->cookie == 0) {
- if (i > 100)
- break;
- i++;
- udelay(2);
- barrier();
- }
- b43_handle_hwtxstatus(ring->dev, hw);
- /* recycle the descriptor buffer. */
- sync_descbuffer_for_device(ring, meta->dmaaddr,
- ring->rx_buffersize);
-
- return;
- }
rxhdr = (struct b43_rxhdr_fw4 *)skb->data;
len = le16_to_cpu(rxhdr->frame_len);
if (len == 0) {
skb_pull(skb, ring->frameoffset);
b43_rx(ring->dev, skb, rxhdr);
- drop:
+drop:
return;
}
void b43_dma_tx_suspend(struct b43_wldev *dev)
{
b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
- b43_dma_tx_suspend_ring(dev->dma.tx_ring0);
- b43_dma_tx_suspend_ring(dev->dma.tx_ring1);
- b43_dma_tx_suspend_ring(dev->dma.tx_ring2);
- b43_dma_tx_suspend_ring(dev->dma.tx_ring3);
- b43_dma_tx_suspend_ring(dev->dma.tx_ring4);
- b43_dma_tx_suspend_ring(dev->dma.tx_ring5);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BK);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BE);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VI);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VO);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring_mcast);
}
void b43_dma_tx_resume(struct b43_wldev *dev)
{
- b43_dma_tx_resume_ring(dev->dma.tx_ring5);
- b43_dma_tx_resume_ring(dev->dma.tx_ring4);
- b43_dma_tx_resume_ring(dev->dma.tx_ring3);
- b43_dma_tx_resume_ring(dev->dma.tx_ring2);
- b43_dma_tx_resume_ring(dev->dma.tx_ring1);
- b43_dma_tx_resume_ring(dev->dma.tx_ring0);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring_mcast);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VO);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VI);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BE);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BK);
b43_power_saving_ctl_bits(dev, 0);
}
enum b43_dmatype type;
/* Boolean. Is this ring stopped at ieee80211 level? */
bool stopped;
+ /* The QOS priority assigned to this ring. Only used for TX rings.
+ * This is the mac80211 "queue" value. */
+ u8 queue_prio;
/* Lock, only used for TX. */
spinlock_t lock;
struct b43_wldev *dev;
int max_used_slots;
/* Last time we injected a ring overflow. */
unsigned long last_injected_overflow;
-#endif /* CONFIG_B43_DEBUG */
+ /* Statistics: Number of successfully transmitted packets */
+ u64 nr_succeed_tx_packets;
+ /* Statistics: Number of failed TX packets */
+ u64 nr_failed_tx_packets;
+ /* Statistics: Total number of TX plus all retries. */
+ u64 nr_total_packet_tries;
+#endif /* CONFIG_B43_DEBUG */
};
static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+int b43_modparam_qos = 1;
+module_param_named(qos, b43_modparam_qos, int, 0444);
+MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
+
+
static const struct ssb_device_id b43_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
* data in there. This data is the same for all devices, so we don't
* get concurrency issues */
#define RATETAB_ENT(_rateid, _flags) \
- { \
- .rate = B43_RATE_TO_BASE100KBPS(_rateid), \
- .val = (_rateid), \
- .val2 = (_rateid), \
- .flags = (_flags), \
+ { \
+ .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
}
+
+/*
+ * NOTE: When changing this, sync with xmit.c's
+ * b43_plcp_get_bitrate_idx_* functions!
+ */
static struct ieee80211_rate __b43_ratetable[] = {
- RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK),
- RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
- RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
- RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
- RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_CCK_RATE_1MB, 0),
+ RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
+ RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
+ RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
+ RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
+ RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
+ RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
+ RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
+ RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
};
#define b43_a_ratetable (__b43_ratetable + 4)
#define b43_g_ratetable (__b43_ratetable + 0)
#define b43_g_ratetable_size 12
-#define CHANTAB_ENT(_chanid, _freq) \
- { \
- .chan = (_chanid), \
- .freq = (_freq), \
- .val = (_chanid), \
- .flag = IEEE80211_CHAN_W_SCAN | \
- IEEE80211_CHAN_W_ACTIVE_SCAN | \
- IEEE80211_CHAN_W_IBSS, \
- .power_level = 0xFF, \
- .antenna_max = 0xFF, \
- }
+#define CHAN4G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
static struct ieee80211_channel b43_2ghz_chantable[] = {
- CHANTAB_ENT(1, 2412),
- CHANTAB_ENT(2, 2417),
- CHANTAB_ENT(3, 2422),
- CHANTAB_ENT(4, 2427),
- CHANTAB_ENT(5, 2432),
- CHANTAB_ENT(6, 2437),
- CHANTAB_ENT(7, 2442),
- CHANTAB_ENT(8, 2447),
- CHANTAB_ENT(9, 2452),
- CHANTAB_ENT(10, 2457),
- CHANTAB_ENT(11, 2462),
- CHANTAB_ENT(12, 2467),
- CHANTAB_ENT(13, 2472),
- CHANTAB_ENT(14, 2484),
+ CHAN4G(1, 2412, 0),
+ CHAN4G(2, 2417, 0),
+ CHAN4G(3, 2422, 0),
+ CHAN4G(4, 2427, 0),
+ CHAN4G(5, 2432, 0),
+ CHAN4G(6, 2437, 0),
+ CHAN4G(7, 2442, 0),
+ CHAN4G(8, 2447, 0),
+ CHAN4G(9, 2452, 0),
+ CHAN4G(10, 2457, 0),
+ CHAN4G(11, 2462, 0),
+ CHAN4G(12, 2467, 0),
+ CHAN4G(13, 2472, 0),
+ CHAN4G(14, 2484, 0),
};
-#define b43_2ghz_chantable_size ARRAY_SIZE(b43_2ghz_chantable)
-
-#if 0
-static struct ieee80211_channel b43_5ghz_chantable[] = {
- CHANTAB_ENT(36, 5180),
- CHANTAB_ENT(40, 5200),
- CHANTAB_ENT(44, 5220),
- CHANTAB_ENT(48, 5240),
- CHANTAB_ENT(52, 5260),
- CHANTAB_ENT(56, 5280),
- CHANTAB_ENT(60, 5300),
- CHANTAB_ENT(64, 5320),
- CHANTAB_ENT(149, 5745),
- CHANTAB_ENT(153, 5765),
- CHANTAB_ENT(157, 5785),
- CHANTAB_ENT(161, 5805),
- CHANTAB_ENT(165, 5825),
+#undef CHAN4G
+
+#define CHAN5G(_channel, _flags) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+static struct ieee80211_channel b43_5ghz_nphy_chantable[] = {
+ CHAN5G(32, 0), CHAN5G(34, 0),
+ CHAN5G(36, 0), CHAN5G(38, 0),
+ CHAN5G(40, 0), CHAN5G(42, 0),
+ CHAN5G(44, 0), CHAN5G(46, 0),
+ CHAN5G(48, 0), CHAN5G(50, 0),
+ CHAN5G(52, 0), CHAN5G(54, 0),
+ CHAN5G(56, 0), CHAN5G(58, 0),
+ CHAN5G(60, 0), CHAN5G(62, 0),
+ CHAN5G(64, 0), CHAN5G(66, 0),
+ CHAN5G(68, 0), CHAN5G(70, 0),
+ CHAN5G(72, 0), CHAN5G(74, 0),
+ CHAN5G(76, 0), CHAN5G(78, 0),
+ CHAN5G(80, 0), CHAN5G(82, 0),
+ CHAN5G(84, 0), CHAN5G(86, 0),
+ CHAN5G(88, 0), CHAN5G(90, 0),
+ CHAN5G(92, 0), CHAN5G(94, 0),
+ CHAN5G(96, 0), CHAN5G(98, 0),
+ CHAN5G(100, 0), CHAN5G(102, 0),
+ CHAN5G(104, 0), CHAN5G(106, 0),
+ CHAN5G(108, 0), CHAN5G(110, 0),
+ CHAN5G(112, 0), CHAN5G(114, 0),
+ CHAN5G(116, 0), CHAN5G(118, 0),
+ CHAN5G(120, 0), CHAN5G(122, 0),
+ CHAN5G(124, 0), CHAN5G(126, 0),
+ CHAN5G(128, 0), CHAN5G(130, 0),
+ CHAN5G(132, 0), CHAN5G(134, 0),
+ CHAN5G(136, 0), CHAN5G(138, 0),
+ CHAN5G(140, 0), CHAN5G(142, 0),
+ CHAN5G(144, 0), CHAN5G(145, 0),
+ CHAN5G(146, 0), CHAN5G(147, 0),
+ CHAN5G(148, 0), CHAN5G(149, 0),
+ CHAN5G(150, 0), CHAN5G(151, 0),
+ CHAN5G(152, 0), CHAN5G(153, 0),
+ CHAN5G(154, 0), CHAN5G(155, 0),
+ CHAN5G(156, 0), CHAN5G(157, 0),
+ CHAN5G(158, 0), CHAN5G(159, 0),
+ CHAN5G(160, 0), CHAN5G(161, 0),
+ CHAN5G(162, 0), CHAN5G(163, 0),
+ CHAN5G(164, 0), CHAN5G(165, 0),
+ CHAN5G(166, 0), CHAN5G(168, 0),
+ CHAN5G(170, 0), CHAN5G(172, 0),
+ CHAN5G(174, 0), CHAN5G(176, 0),
+ CHAN5G(178, 0), CHAN5G(180, 0),
+ CHAN5G(182, 0), CHAN5G(184, 0),
+ CHAN5G(186, 0), CHAN5G(188, 0),
+ CHAN5G(190, 0), CHAN5G(192, 0),
+ CHAN5G(194, 0), CHAN5G(196, 0),
+ CHAN5G(198, 0), CHAN5G(200, 0),
+ CHAN5G(202, 0), CHAN5G(204, 0),
+ CHAN5G(206, 0), CHAN5G(208, 0),
+ CHAN5G(210, 0), CHAN5G(212, 0),
+ CHAN5G(214, 0), CHAN5G(216, 0),
+ CHAN5G(218, 0), CHAN5G(220, 0),
+ CHAN5G(222, 0), CHAN5G(224, 0),
+ CHAN5G(226, 0), CHAN5G(228, 0),
+};
+
+static struct ieee80211_channel b43_5ghz_aphy_chantable[] = {
+ CHAN5G(34, 0), CHAN5G(36, 0),
+ CHAN5G(38, 0), CHAN5G(40, 0),
+ CHAN5G(42, 0), CHAN5G(44, 0),
+ CHAN5G(46, 0), CHAN5G(48, 0),
+ CHAN5G(52, 0), CHAN5G(56, 0),
+ CHAN5G(60, 0), CHAN5G(64, 0),
+ CHAN5G(100, 0), CHAN5G(104, 0),
+ CHAN5G(108, 0), CHAN5G(112, 0),
+ CHAN5G(116, 0), CHAN5G(120, 0),
+ CHAN5G(124, 0), CHAN5G(128, 0),
+ CHAN5G(132, 0), CHAN5G(136, 0),
+ CHAN5G(140, 0), CHAN5G(149, 0),
+ CHAN5G(153, 0), CHAN5G(157, 0),
+ CHAN5G(161, 0), CHAN5G(165, 0),
+ CHAN5G(184, 0), CHAN5G(188, 0),
+ CHAN5G(192, 0), CHAN5G(196, 0),
+ CHAN5G(200, 0), CHAN5G(204, 0),
+ CHAN5G(208, 0), CHAN5G(212, 0),
+ CHAN5G(216, 0),
+};
+#undef CHAN5G
+
+static struct ieee80211_supported_band b43_band_5GHz_nphy = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = b43_5ghz_nphy_chantable,
+ .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable),
+ .bitrates = b43_a_ratetable,
+ .n_bitrates = b43_a_ratetable_size,
+};
+
+static struct ieee80211_supported_band b43_band_5GHz_aphy = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = b43_5ghz_aphy_chantable,
+ .n_channels = ARRAY_SIZE(b43_5ghz_aphy_chantable),
+ .bitrates = b43_a_ratetable,
+ .n_bitrates = b43_a_ratetable_size,
+};
+
+static struct ieee80211_supported_band b43_band_2GHz = {
+ .band = IEEE80211_BAND_2GHZ,
+ .channels = b43_2ghz_chantable,
+ .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
+ .bitrates = b43_g_ratetable,
+ .n_bitrates = b43_g_ratetable_size,
};
-#define b43_5ghz_chantable_size ARRAY_SIZE(b43_5ghz_chantable)
-#endif
static void b43_wireless_core_exit(struct b43_wldev *dev);
static int b43_wireless_core_init(struct b43_wldev *dev);
}
/* Read HostFlags */
-u32 b43_hf_read(struct b43_wldev * dev)
+u64 b43_hf_read(struct b43_wldev * dev)
{
- u32 ret;
+ u64 ret;
ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
ret <<= 16;
+ ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI);
+ ret <<= 16;
ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
return ret;
}
/* Write HostFlags */
-void b43_hf_write(struct b43_wldev *dev, u32 value)
+void b43_hf_write(struct b43_wldev *dev, u64 value)
{
- b43_shm_write16(dev, B43_SHM_SHARED,
- B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF));
- b43_shm_write16(dev, B43_SHM_SHARED,
- B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16));
+ u16 lo, mi, hi;
+
+ lo = (value & 0x00000000FFFFULL);
+ mi = (value & 0x0000FFFF0000ULL) >> 16;
+ hi = (value & 0xFFFF00000000ULL) >> 32;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
}
void b43_tsf_read(struct b43_wldev *dev, u64 * tsf)
}
static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
- u16 shm_offset, u16 size, u8 rate)
+ u16 shm_offset, u16 size,
+ struct ieee80211_rate *rate)
{
struct b43_plcp_hdr4 plcp;
u32 tmp;
__le16 dur;
plcp.data = 0;
- b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
dur = ieee80211_generic_frame_duration(dev->wl->hw,
dev->wl->vif, size,
- B43_RATE_TO_BASE100KBPS(rate));
+ rate);
/* Write PLCP in two parts and timing for packet transfer */
tmp = le32_to_cpu(plcp.data);
b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
* 3) Stripping TIM
*/
static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
- u16 *dest_size, u8 rate)
+ u16 *dest_size,
+ struct ieee80211_rate *rate)
{
const u8 *src_data;
u8 *dest_data;
IEEE80211_STYPE_PROBE_RESP);
dur = ieee80211_generic_frame_duration(dev->wl->hw,
dev->wl->vif, *dest_size,
- B43_RATE_TO_BASE100KBPS(rate));
+ rate);
hdr->duration_id = dur;
return dest_data;
static void b43_write_probe_resp_template(struct b43_wldev *dev,
u16 ram_offset,
- u16 shm_size_offset, u8 rate)
+ u16 shm_size_offset,
+ struct ieee80211_rate *rate)
{
const u8 *probe_resp_data;
u16 size;
/* Looks like PLCP headers plus packet timings are stored for
* all possible basic rates
*/
- b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB);
- b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB);
- b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB);
- b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB);
+ b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
+ b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
+ b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
+ b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
b43_write_template_common(dev, probe_resp_data,
- size, ram_offset, shm_size_offset, rate);
+ size, ram_offset, shm_size_offset,
+ rate->hw_value);
kfree(probe_resp_data);
}
b43_write_beacon_template(dev, 0x68, 0x18,
B43_CCK_RATE_1MB);
b43_write_probe_resp_template(dev, 0x268, 0x4A,
- B43_CCK_RATE_11MB);
+ &__b43_ratetable[3]);
wl->beacon0_uploaded = 1;
}
cmd |= B43_MACCMD_BEACON0_VALID;
/* Check the DMA reason registers for received data. */
if (dma_reason[0] & B43_DMAIRQ_RX_DONE)
- b43_dma_rx(dev->dma.rx_ring0);
- if (dma_reason[3] & B43_DMAIRQ_RX_DONE)
- b43_dma_rx(dev->dma.rx_ring3);
+ b43_dma_rx(dev->dma.rx_ring);
B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
+ B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
}
/* http://bcm-specs.sipsolutions.net/EnableMac */
-void b43_mac_enable(struct b43_wldev *dev)
+static void b43_mac_enable(struct b43_wldev *dev)
{
dev->mac_suspended--;
B43_WARN_ON(dev->mac_suspended < 0);
}
/* http://bcm-specs.sipsolutions.net/SuspendMAC */
-void b43_mac_suspend(struct b43_wldev *dev)
+static void b43_mac_suspend(struct b43_wldev *dev)
{
int i;
u32 tmp;
return NETDEV_TX_OK;
}
+/* Locking: wl->irq_lock */
+static void b43_qos_params_upload(struct b43_wldev *dev,
+ const struct ieee80211_tx_queue_params *p,
+ u16 shm_offset)
+{
+ u16 params[B43_NR_QOSPARAMS];
+ int cw_min, cw_max, aifs, bslots, tmp;
+ unsigned int i;
+
+ const u16 aCWmin = 0x0001;
+ const u16 aCWmax = 0x03FF;
+
+ /* Calculate the default values for the parameters, if needed. */
+ switch (shm_offset) {
+ case B43_QOS_VOICE:
+ aifs = (p->aifs == -1) ? 2 : p->aifs;
+ cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min;
+ cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max;
+ break;
+ case B43_QOS_VIDEO:
+ aifs = (p->aifs == -1) ? 2 : p->aifs;
+ cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min;
+ cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max;
+ break;
+ case B43_QOS_BESTEFFORT:
+ aifs = (p->aifs == -1) ? 3 : p->aifs;
+ cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
+ cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
+ break;
+ case B43_QOS_BACKGROUND:
+ aifs = (p->aifs == -1) ? 7 : p->aifs;
+ cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
+ cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
+ break;
+ default:
+ B43_WARN_ON(1);
+ return;
+ }
+ if (cw_min <= 0)
+ cw_min = aCWmin;
+ if (cw_max <= 0)
+ cw_max = aCWmin;
+ bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min;
+
+ memset(¶ms, 0, sizeof(params));
+
+ params[B43_QOSPARAM_TXOP] = p->txop * 32;
+ params[B43_QOSPARAM_CWMIN] = cw_min;
+ params[B43_QOSPARAM_CWMAX] = cw_max;
+ params[B43_QOSPARAM_CWCUR] = cw_min;
+ params[B43_QOSPARAM_AIFS] = aifs;
+ params[B43_QOSPARAM_BSLOTS] = bslots;
+ params[B43_QOSPARAM_REGGAP] = bslots + aifs;
+
+ for (i = 0; i < ARRAY_SIZE(params); i++) {
+ if (i == B43_QOSPARAM_STATUS) {
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED,
+ shm_offset + (i * 2));
+ /* Mark the parameters as updated. */
+ tmp |= 0x100;
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ shm_offset + (i * 2),
+ tmp);
+ } else {
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ shm_offset + (i * 2),
+ params[i]);
+ }
+ }
+}
+
+/* Update the QOS parameters in hardware. */
+static void b43_qos_update(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct b43_qos_params *params;
+ unsigned long flags;
+ unsigned int i;
+
+ /* Mapping of mac80211 queues to b43 SHM offsets. */
+ static const u16 qos_shm_offsets[] = {
+ [0] = B43_QOS_VOICE,
+ [1] = B43_QOS_VIDEO,
+ [2] = B43_QOS_BESTEFFORT,
+ [3] = B43_QOS_BACKGROUND,
+ };
+ BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params));
+
+ b43_mac_suspend(dev);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
+ params = &(wl->qos_params[i]);
+ if (params->need_hw_update) {
+ b43_qos_params_upload(dev, &(params->p),
+ qos_shm_offsets[i]);
+ params->need_hw_update = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43_mac_enable(dev);
+}
+
+static void b43_qos_clear(struct b43_wl *wl)
+{
+ struct b43_qos_params *params;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
+ params = &(wl->qos_params[i]);
+
+ memset(&(params->p), 0, sizeof(params->p));
+ params->p.aifs = -1;
+ params->need_hw_update = 1;
+ }
+}
+
+/* Initialize the core's QOS capabilities */
+static void b43_qos_init(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ unsigned int i;
+
+ /* Upload the current QOS parameters. */
+ for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++)
+ wl->qos_params[i].need_hw_update = 1;
+ b43_qos_update(dev);
+
+ /* Enable QOS support. */
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
+ b43_write16(dev, B43_MMIO_IFSCTL,
+ b43_read16(dev, B43_MMIO_IFSCTL)
+ | B43_MMIO_IFSCTL_USE_EDCF);
+}
+
+static void b43_qos_update_work(struct work_struct *work)
+{
+ struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work);
+ struct b43_wldev *dev;
+
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED)))
+ b43_qos_update(dev);
+ mutex_unlock(&wl->mutex);
+}
+
static int b43_op_conf_tx(struct ieee80211_hw *hw,
- int queue,
+ int _queue,
const struct ieee80211_tx_queue_params *params)
{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ unsigned long flags;
+ unsigned int queue = (unsigned int)_queue;
+ struct b43_qos_params *p;
+
+ if (queue >= ARRAY_SIZE(wl->qos_params)) {
+ /* Queue not available or don't support setting
+ * params on this queue. Return success to not
+ * confuse mac80211. */
+ return 0;
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ p = &(wl->qos_params[queue]);
+ memcpy(&(p->p), params, sizeof(p->p));
+ p->need_hw_update = 1;
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ queue_work(hw->workqueue, &wl->qos_update_work);
+
return 0;
}
return 0;
}
-static const char *phymode_to_string(unsigned int phymode)
-{
- switch (phymode) {
- case B43_PHYMODE_A:
- return "A";
- case B43_PHYMODE_B:
- return "B";
- case B43_PHYMODE_G:
- return "G";
- default:
- B43_WARN_ON(1);
- }
- return "";
-}
-
-static int find_wldev_for_phymode(struct b43_wl *wl,
- unsigned int phymode,
- struct b43_wldev **dev, bool * gmode)
-{
- struct b43_wldev *d;
-
- list_for_each_entry(d, &wl->devlist, list) {
- if (d->phy.possible_phymodes & phymode) {
- /* Ok, this device supports the PHY-mode.
- * Now figure out how the gmode bit has to be
- * set to support it. */
- if (phymode == B43_PHYMODE_A)
- *gmode = 0;
- else
- *gmode = 1;
- *dev = d;
-
- return 0;
- }
- }
-
- return -ESRCH;
-}
-
static void b43_put_phy_into_reset(struct b43_wldev *dev)
{
struct ssb_device *sdev = dev->dev;
msleep(1);
}
+static const char * band_to_string(enum ieee80211_band band)
+{
+ switch (band) {
+ case IEEE80211_BAND_5GHZ:
+ return "5";
+ case IEEE80211_BAND_2GHZ:
+ return "2.4";
+ default:
+ break;
+ }
+ B43_WARN_ON(1);
+ return "";
+}
+
/* Expects wl->mutex locked */
-static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
+static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)
{
- struct b43_wldev *up_dev;
+ struct b43_wldev *up_dev = NULL;
struct b43_wldev *down_dev;
+ struct b43_wldev *d;
int err;
- bool gmode = 0;
+ bool gmode;
int prev_status;
- err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
- if (err) {
- b43err(wl, "Could not find a device for %s-PHY mode\n",
- phymode_to_string(new_mode));
- return err;
+ /* Find a device and PHY which supports the band. */
+ list_for_each_entry(d, &wl->devlist, list) {
+ switch (chan->band) {
+ case IEEE80211_BAND_5GHZ:
+ if (d->phy.supports_5ghz) {
+ up_dev = d;
+ gmode = 0;
+ }
+ break;
+ case IEEE80211_BAND_2GHZ:
+ if (d->phy.supports_2ghz) {
+ up_dev = d;
+ gmode = 1;
+ }
+ break;
+ default:
+ B43_WARN_ON(1);
+ return -EINVAL;
+ }
+ if (up_dev)
+ break;
+ }
+ if (!up_dev) {
+ b43err(wl, "Could not find a device for %s-GHz band operation\n",
+ band_to_string(chan->band));
+ return -ENODEV;
}
if ((up_dev == wl->current_dev) &&
(!!wl->current_dev->phy.gmode == !!gmode)) {
/* This device is already running. */
return 0;
}
- b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
- phymode_to_string(new_mode));
+ b43dbg(wl, "Switching to %s-GHz band\n",
+ band_to_string(chan->band));
down_dev = wl->current_dev;
prev_status = b43_status(down_dev);
err = b43_wireless_core_init(up_dev);
if (err) {
b43err(wl, "Fatal: Could not initialize device for "
- "newly selected %s-PHY mode\n",
- phymode_to_string(new_mode));
+ "selected %s-GHz band\n",
+ band_to_string(chan->band));
goto init_failure;
}
}
err = b43_wireless_core_start(up_dev);
if (err) {
b43err(wl, "Fatal: Coult not start device for "
- "newly selected %s-PHY mode\n",
- phymode_to_string(new_mode));
+ "selected %s-GHz band\n",
+ band_to_string(chan->band));
b43_wireless_core_exit(up_dev);
goto init_failure;
}
wl->current_dev = up_dev;
return 0;
- init_failure:
+init_failure:
/* Whoops, failed to init the new core. No core is operating now. */
wl->current_dev = NULL;
return err;
struct b43_wldev *dev;
struct b43_phy *phy;
unsigned long flags;
- unsigned int new_phymode = 0xFFFF;
int antenna;
int err = 0;
u32 savedirqs;
mutex_lock(&wl->mutex);
- /* Switch the PHY mode (if necessary). */
- switch (conf->phymode) {
- case MODE_IEEE80211A:
- new_phymode = B43_PHYMODE_A;
- break;
- case MODE_IEEE80211B:
- new_phymode = B43_PHYMODE_B;
- break;
- case MODE_IEEE80211G:
- new_phymode = B43_PHYMODE_G;
- break;
- default:
- B43_WARN_ON(1);
- }
- err = b43_switch_phymode(wl, new_phymode);
+ /* Switch the band (if necessary). This might change the active core. */
+ err = b43_switch_band(wl, conf->channel);
if (err)
goto out_unlock_mutex;
dev = wl->current_dev;
/* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */
- if (conf->channel_val != phy->channel)
- b43_radio_selectchannel(dev, conf->channel_val, 0);
+ if (conf->channel->hw_value != phy->channel)
+ b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
/* Enable/Disable ShortSlot timing. */
if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
memset(wl->mac_addr, 0, ETH_ALEN);
wl->filter_flags = 0;
wl->radiotap_enabled = 0;
+ b43_qos_clear(wl);
/* First register RFkill.
* LEDs that are registered later depend on it. */
struct b43_wldev *dev = wl->current_dev;
b43_rfkill_exit(dev);
+ cancel_work_sync(&(wl->qos_update_work));
mutex_lock(&wl->mutex);
if (b43_status(dev) >= B43_STAT_STARTED)
return 0;
}
+static void b43_op_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd notify_cmd,
+ const u8 *addr)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+
+ B43_WARN_ON(!vif || wl->vif != vif);
+}
+
static const struct ieee80211_ops b43_hw_ops = {
.tx = b43_op_tx,
.conf_tx = b43_op_conf_tx,
.set_retry_limit = b43_op_set_retry_limit,
.set_tim = b43_op_beacon_set_tim,
.beacon_update = b43_op_ibss_beacon_update,
+ .sta_notify = b43_op_sta_notify,
};
/* Hard-reset the chip. Do not call this directly.
b43info(wl, "Controller restarted\n");
}
-static int b43_setup_modes(struct b43_wldev *dev,
+static int b43_setup_bands(struct b43_wldev *dev,
bool have_2ghz_phy, bool have_5ghz_phy)
{
struct ieee80211_hw *hw = dev->wl->hw;
- struct ieee80211_hw_mode *mode;
- struct b43_phy *phy = &dev->phy;
- int err;
- /* XXX: This function will go away soon, when mac80211
- * band stuff is rewritten. So this is just a hack.
- * For now we always claim GPHY mode, as there is no
- * support for NPHY and APHY in the device, yet.
- * This assumption is OK, as any B, N or A PHY will already
- * have died a horrible sanity check death earlier. */
-
- mode = &phy->hwmodes[0];
- mode->mode = MODE_IEEE80211G;
- mode->num_channels = b43_2ghz_chantable_size;
- mode->channels = b43_2ghz_chantable;
- mode->num_rates = b43_g_ratetable_size;
- mode->rates = b43_g_ratetable;
- err = ieee80211_register_hwmode(hw, mode);
- if (err)
- return err;
- phy->possible_phymodes |= B43_PHYMODE_G;
+ if (have_2ghz_phy)
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
+ if (dev->phy.type == B43_PHYTYPE_N) {
+ if (have_5ghz_phy)
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy;
+ } else {
+ if (have_5ghz_phy)
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy;
+ }
+
+ dev->phy.supports_2ghz = have_2ghz_phy;
+ dev->phy.supports_5ghz = have_5ghz_phy;
return 0;
}
err = b43_validate_chipaccess(dev);
if (err)
goto err_powerdown;
- err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy);
+ err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
if (err)
goto err_powerdown;
hw->max_signal = 100;
hw->max_rssi = -110;
hw->max_noise = -110;
- hw->queues = 1; /* FIXME: hardware has more queues */
+ hw->queues = b43_modparam_qos ? 4 : 1;
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
spin_lock_init(&wl->shm_lock);
mutex_init(&wl->mutex);
INIT_LIST_HEAD(&wl->devlist);
+ INIT_WORK(&wl->qos_update_work, b43_qos_update_work);
ssb_set_devtypedata(dev, wl);
b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
/* Magic helper macro to pad structures. Ignore those above. It's magic. */
#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
+
+extern int b43_modparam_qos;
+
+
/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
static inline u8 b43_freq_to_channel_5ghz(int freq)
{
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
-u32 b43_hf_read(struct b43_wldev *dev);
-void b43_hf_write(struct b43_wldev *dev, u32 value);
+u64 b43_hf_read(struct b43_wldev *dev);
+void b43_hf_write(struct b43_wldev *dev, u64 value);
void b43_dummy_transmission(struct b43_wldev *dev);
void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
-void b43_mac_suspend(struct b43_wldev *dev);
-void b43_mac_enable(struct b43_wldev *dev);
-
void b43_controller_restart(struct b43_wldev *dev, const char *reason);
#define B43_PS_ENABLED (1 << 0) /* Force enable hardware power saving */
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 b43_attr_interfmode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
static DEVICE_ATTR(interference, 0644,
b43_attr_interfmode_show, b43_attr_interfmode_store);
-static ssize_t b43_attr_preamble_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct b43_wldev *wldev = dev_to_b43_wldev(dev);
- ssize_t count;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- mutex_lock(&wldev->wl->mutex);
-
- if (wldev->short_preamble)
- count =
- snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
- else
- count =
- snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
-
- mutex_unlock(&wldev->wl->mutex);
-
- return count;
-}
-
-static ssize_t b43_attr_preamble_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct b43_wldev *wldev = dev_to_b43_wldev(dev);
- unsigned long flags;
- int value;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- value = get_boolean(buf, count);
- if (value < 0)
- return value;
- mutex_lock(&wldev->wl->mutex);
- spin_lock_irqsave(&wldev->wl->irq_lock, flags);
-
- wldev->short_preamble = !!value;
-
- spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
- mutex_unlock(&wldev->wl->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(shortpreamble, 0644,
- b43_attr_preamble_show, b43_attr_preamble_store);
-
int b43_sysfs_register(struct b43_wldev *wldev)
{
struct device *dev = wldev->dev->dev;
- int err;
B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
- err = device_create_file(dev, &dev_attr_interference);
- if (err)
- goto out;
- err = device_create_file(dev, &dev_attr_shortpreamble);
- if (err)
- goto err_remove_interfmode;
-
- out:
- return err;
- err_remove_interfmode:
- device_remove_file(dev, &dev_attr_interference);
- goto out;
+ return device_create_file(dev, &dev_attr_interference);
}
void b43_sysfs_unregister(struct b43_wldev *wldev)
{
struct device *dev = wldev->dev->dev;
- device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &dev_attr_interference);
}
b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]);
}
+static void b43_write_null_nst(struct b43_wldev *dev)
+{
+ int i;
+
+ for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+ b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, 0);
+}
+
+static void b43_write_nst(struct b43_wldev *dev, const u16 *nst)
+{
+ int i;
+
+ for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+ b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, nst[i]);
+}
+
static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */
{
struct b43_phy *phy = &dev->phy;
- int i;
if (phy->type == B43_PHYTYPE_A) {
if (phy->rev <= 1)
- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
- i, 0);
+ b43_write_null_nst(dev);
else if (phy->rev == 2)
- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
- i, b43_tab_noisescalea2[i]);
+ b43_write_nst(dev, b43_tab_noisescalea2);
else if (phy->rev == 3)
- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
- i, b43_tab_noisescalea3[i]);
+ b43_write_nst(dev, b43_tab_noisescalea3);
else
- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
- i, b43_tab_noisescaleg3[i]);
+ b43_write_nst(dev, b43_tab_noisescaleg3);
} else {
if (phy->rev >= 6) {
if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
- i, b43_tab_noisescaleg3[i]);
+ b43_write_nst(dev, b43_tab_noisescaleg3);
else
- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
- i, b43_tab_noisescaleg2[i]);
+ b43_write_nst(dev, b43_tab_noisescaleg2);
} else {
- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
- i, b43_tab_noisescaleg1[i]);
+ b43_write_nst(dev, b43_tab_noisescaleg1);
}
}
}
#include "dma.h"
-/* Extract the bitrate out of a CCK PLCP header. */
-static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
+/* Extract the bitrate index out of a CCK PLCP header. */
+static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
{
switch (plcp->raw[0]) {
case 0x0A:
- return B43_CCK_RATE_1MB;
+ return 0;
case 0x14:
- return B43_CCK_RATE_2MB;
+ return 1;
case 0x37:
- return B43_CCK_RATE_5MB;
+ return 2;
case 0x6E:
- return B43_CCK_RATE_11MB;
+ return 3;
}
B43_WARN_ON(1);
- return 0;
+ return -1;
}
-/* Extract the bitrate out of an OFDM PLCP header. */
-static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
+/* Extract the bitrate index out of an OFDM PLCP header. */
+static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy)
{
+ int base = aphy ? 0 : 4;
+
switch (plcp->raw[0] & 0xF) {
case 0xB:
- return B43_OFDM_RATE_6MB;
+ return base + 0;
case 0xF:
- return B43_OFDM_RATE_9MB;
+ return base + 1;
case 0xA:
- return B43_OFDM_RATE_12MB;
+ return base + 2;
case 0xE:
- return B43_OFDM_RATE_18MB;
+ return base + 3;
case 0x9:
- return B43_OFDM_RATE_24MB;
+ return base + 4;
case 0xD:
- return B43_OFDM_RATE_36MB;
+ return base + 5;
case 0x8:
- return B43_OFDM_RATE_48MB;
+ return base + 6;
case 0xC:
- return B43_OFDM_RATE_54MB;
+ return base + 7;
}
B43_WARN_ON(1);
- return 0;
+ return -1;
}
u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
(const struct ieee80211_hdr *)fragment_data;
int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
u16 fctl = le16_to_cpu(wlhdr->frame_control);
+ struct ieee80211_rate *fbrate;
u8 rate, rate_fb;
int rate_ofdm, rate_fb_ofdm;
unsigned int plcp_fragment_len;
memset(txhdr, 0, sizeof(*txhdr));
- rate = txctl->tx_rate;
+ WARN_ON(!txctl->tx_rate);
+ rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB;
rate_ofdm = b43_is_ofdm_rate(rate);
- rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+ fbrate = txctl->alt_retry_rate ? : txctl->tx_rate;
+ rate_fb = fbrate->hw_value;
rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
if (rate_ofdm)
* use the original dur_id field. */
txhdr->dur_fb = wlhdr->duration_id;
} else {
- int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
txctl->vif,
fragment_len,
- fbrate_base100kbps);
+ fbrate);
}
plcp_fragment_len = fragment_len + FCS_LEN;
phy_ctl |= B43_TXH_PHY_ENC_OFDM;
else
phy_ctl |= B43_TXH_PHY_ENC_CCK;
- if (dev->short_preamble)
+ if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
int rts_rate_ofdm, rts_rate_fb_ofdm;
struct b43_plcp_hdr6 *plcp;
- rts_rate = txctl->rts_cts_rate;
+ WARN_ON(!txctl->rts_cts_rate);
+ rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
rts_rate_fb = b43_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
u16 phystat0, phystat3, chanstat, mactime;
u32 macstat;
u16 chanid;
+ u16 phytype;
u8 jssi;
int padding;
macstat = le32_to_cpu(rxhdr->mac_status);
mactime = le16_to_cpu(rxhdr->mac_time);
chanstat = le16_to_cpu(rxhdr->channel);
+ phytype = chanstat & B43_RX_CHAN_PHYTYPE;
if (macstat & B43_RX_MAC_FCSERR)
dev->wl->ieee_stats.dot11FCSErrorCount++;
/* the next line looks wrong, but is what mac80211 wants */
status.signal = (jssi * 100) / B43_RX_MAX_SSI;
if (phystat0 & B43_RX_PHYST0_OFDM)
- status.rate = b43_plcp_get_bitrate_ofdm(plcp);
+ status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,
+ phytype == B43_PHYTYPE_A);
else
- status.rate = b43_plcp_get_bitrate_cck(plcp);
+ status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
/*
- * If monitors are present get full 64-bit timestamp. This
- * code assumes we get to process the packet within 16 bits
- * of timestamp, i.e. about 65 milliseconds after the PHY
- * received the first symbol.
+ * All frames on monitor interfaces and beacons always need a full
+ * 64-bit timestamp. Monitor interfaces need it for diagnostic
+ * purposes and beacons for IBSS merging.
+ * This code assumes we get to process the packet within 16 bits
+ * of timestamp, i.e. about 65 milliseconds after the PHY received
+ * the first symbol.
*/
- if (dev->wl->radiotap_enabled) {
+ if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
+ == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
+ dev->wl->radiotap_enabled) {
u16 low_mactime_now;
b43_tsf_read(dev, &status.mactime);
chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
switch (chanstat & B43_RX_CHAN_PHYTYPE) {
case B43_PHYTYPE_A:
- status.phymode = MODE_IEEE80211A;
+ status.band = IEEE80211_BAND_5GHZ;
B43_WARN_ON(1);
/* FIXME: We don't really know which value the "chanid" contains.
* So the following assignment might be wrong. */
- status.channel = chanid;
- status.freq = b43_channel_to_freq_5ghz(status.channel);
+ status.freq = b43_channel_to_freq_5ghz(chanid);
break;
case B43_PHYTYPE_G:
- status.phymode = MODE_IEEE80211G;
+ status.band = IEEE80211_BAND_2GHZ;
/* chanid is the radio channel cookie value as used
* to tune the radio. */
status.freq = chanid + 2400;
- status.channel = b43_freq_to_channel_2ghz(status.freq);
break;
case B43_PHYTYPE_N:
- status.phymode = 0xDEAD /*FIXME MODE_IEEE80211N*/;
/* chanid is the SHM channel cookie. Which is the plain
* channel number in b43. */
- status.channel = chanid;
- if (chanstat & B43_RX_CHAN_5GHZ)
- status.freq = b43_freq_to_channel_5ghz(status.freq);
- else
- status.freq = b43_freq_to_channel_2ghz(status.freq);
+ if (chanstat & B43_RX_CHAN_5GHZ) {
+ status.band = IEEE80211_BAND_5GHZ;
+ status.freq = b43_freq_to_channel_5ghz(chanid);
+ } else {
+ status.band = IEEE80211_BAND_2GHZ;
+ status.freq = b43_freq_to_channel_2ghz(chanid);
+ }
break;
default:
B43_WARN_ON(1);
{
b43_dma_tx_resume(dev);
}
-
-#if 0
-static void upload_qos_parms(struct b43_wldev *dev,
- const u16 * parms, u16 offset)
-{
- int i;
-
- for (i = 0; i < B43_NR_QOSPARMS; i++) {
- b43_shm_write16(dev, B43_SHM_SHARED,
- offset + (i * 2), parms[i]);
- }
-}
-#endif
-
-/* Initialize the QoS parameters */
-void b43_qos_init(struct b43_wldev *dev)
-{
- /* FIXME: This function must probably be called from the mac80211
- * config callback. */
- return;
-
- b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
- //FIXME kill magic
- b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4);
-
- /*TODO: We might need some stack support here to get the values. */
-}
void b43_tx_suspend(struct b43_wldev *dev);
void b43_tx_resume(struct b43_wldev *dev);
-#define B43_NR_QOSPARMS 22
-enum {
- B43_QOSPARM_TXOP = 0,
- B43_QOSPARM_CWMIN,
- B43_QOSPARM_CWMAX,
- B43_QOSPARM_CWCUR,
- B43_QOSPARM_AIFS,
- B43_QOSPARM_BSLOTS,
- B43_QOSPARM_REGGAP,
- B43_QOSPARM_STATUS,
-};
-void b43_qos_init(struct b43_wldev *dev);
/* Helper functions for converting the key-table index from "firmware-format"
* to "raw-format" and back. The firmware API changed for this at some revision.
#define B43legacy_SHM_SH_HOSTFHI 0x0060 /* Hostflags ucode opts (high) */
/* SHM_SHARED crypto engine */
#define B43legacy_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block */
-/* SHM_SHARED beacon variables */
+/* SHM_SHARED beacon/AP variables */
+#define B43legacy_SHM_SH_DTIMP 0x0012 /* DTIM period */
+#define B43legacy_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
+#define B43legacy_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
+#define B43legacy_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
+#define B43legacy_SHM_SH_TIMPOS 0x001E /* TIM position in beacon */
#define B43legacy_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word */
/* SHM_SHARED ACK/CTS control */
#define B43legacy_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word */
/* SHM_SHARED probe response variables */
-#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */
+#define B43legacy_SHM_SH_PRTLEN 0x004A /* Probe Response template length */
#define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
+#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */
/* SHM_SHARED rate tables */
/* SHM_SHARED microcode soft registers */
#define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
#define B43legacy_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */
#define B43legacy_MACCTL_GMODE 0x80000000 /* G Mode */
+/* MAC Command bitfield */
+#define B43legacy_MACCMD_BEACON0_VALID 0x00000001 /* Beacon 0 in template RAM is busy/valid */
+#define B43legacy_MACCMD_BEACON1_VALID 0x00000002 /* Beacon 1 in template RAM is busy/valid */
+#define B43legacy_MACCMD_DFQ_VALID 0x00000004 /* Directed frame queue valid (IBSS PS mode, ATIM) */
+#define B43legacy_MACCMD_CCA 0x00000008 /* Clear channel assessment */
+#define B43legacy_MACCMD_BGNOISE 0x00000010 /* Background noise */
+
/* 802.11 core specific TM State Low flags */
#define B43legacy_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
#define B43legacy_TMSLOW_PLLREFSEL 0x00200000 /* PLL Freq Ref Select */
# undef assert
#endif
#ifdef CONFIG_B43LEGACY_DEBUG
-# define B43legacy_WARN_ON(expr) \
- do { \
- if (unlikely((expr))) { \
- printk(KERN_INFO PFX "Test (%s) failed at:" \
- " %s:%d:%s()\n", \
- #expr, __FILE__, \
- __LINE__, __FUNCTION__); \
- } \
- } while (0)
+# define B43legacy_WARN_ON(x) WARN_ON(x)
# define B43legacy_BUG_ON(expr) \
do { \
if (unlikely((expr))) { \
} while (0)
# define B43legacy_DEBUG 1
#else
-# define B43legacy_WARN_ON(x) do { /* nothing */ } while (0)
+/* This will evaluate the argument even if debugging is disabled. */
+static inline bool __b43legacy_warn_on_dummy(bool x) { return x; }
+# define B43legacy_WARN_ON(x) __b43legacy_warn_on_dummy(unlikely(!!(x)))
# define B43legacy_BUG_ON(x) do { /* nothing */ } while (0)
# define B43legacy_DEBUG 0
#endif
u8 possible_phymodes;
/* GMODE bit enabled in MACCTL? */
bool gmode;
- /* Possible ieee80211 subsystem hwmodes for this PHY.
- * Which mode is selected, depends on thr GMODE enabled bit */
-#define B43legacy_MAX_PHYHWMODES 2
- struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES];
/* Analog Type */
u8 analog;
u8 nr_devs;
bool radiotap_enabled;
+
+ /* The beacon we are currently using (AP or IBSS mode).
+ * This beacon stuff is protected by the irq_lock. */
+ struct sk_buff *current_beacon;
+ bool beacon0_uploaded;
+ bool beacon1_uploaded;
};
/* Pointers to the firmware data and meta information about it. */
bool __using_pio; /* Using pio rather than dma. */
bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
- bool reg124_set_0x4; /* Variable to keep track of IRQ. */
+ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM). */
bool short_preamble; /* TRUE if using short preamble. */
bool short_slot; /* TRUE if using short slot timing. */
bool radio_hw_enable; /* State of radio hardware enable bit. */
u8 max_nr_keys;
struct b43legacy_key key[58];
- /* Cached beacon template while uploading the template. */
- struct sk_buff *cached_beacon;
-
/* Firmware data */
struct b43legacy_firmware fw;
* data in there. This data is the same for all devices, so we don't
* get concurrency issues */
#define RATETAB_ENT(_rateid, _flags) \
- { \
- .rate = B43legacy_RATE_TO_100KBPS(_rateid), \
- .val = (_rateid), \
- .val2 = (_rateid), \
- .flags = (_flags), \
+ { \
+ .bitrate = B43legacy_RATE_TO_100KBPS(_rateid), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
}
+/*
+ * NOTE: When changing this, sync with xmit.c's
+ * b43legacy_plcp_get_bitrate_idx_* functions!
+ */
static struct ieee80211_rate __b43legacy_ratetable[] = {
- RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK),
- RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
- RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
- RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
- RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
- RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_CCK_RATE_1MB, 0),
+ RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(B43legacy_OFDM_RATE_6MB, 0),
+ RATETAB_ENT(B43legacy_OFDM_RATE_9MB, 0),
+ RATETAB_ENT(B43legacy_OFDM_RATE_12MB, 0),
+ RATETAB_ENT(B43legacy_OFDM_RATE_18MB, 0),
+ RATETAB_ENT(B43legacy_OFDM_RATE_24MB, 0),
+ RATETAB_ENT(B43legacy_OFDM_RATE_36MB, 0),
+ RATETAB_ENT(B43legacy_OFDM_RATE_48MB, 0),
+ RATETAB_ENT(B43legacy_OFDM_RATE_54MB, 0),
};
-#define b43legacy_a_ratetable (__b43legacy_ratetable + 4)
-#define b43legacy_a_ratetable_size 8
#define b43legacy_b_ratetable (__b43legacy_ratetable + 0)
#define b43legacy_b_ratetable_size 4
#define b43legacy_g_ratetable (__b43legacy_ratetable + 0)
#define CHANTAB_ENT(_chanid, _freq) \
{ \
- .chan = (_chanid), \
- .freq = (_freq), \
- .val = (_chanid), \
- .flag = IEEE80211_CHAN_W_SCAN | \
- IEEE80211_CHAN_W_ACTIVE_SCAN | \
- IEEE80211_CHAN_W_IBSS, \
- .power_level = 0x0A, \
- .antenna_max = 0xFF, \
+ .center_freq = (_freq), \
+ .hw_value = (_chanid), \
}
static struct ieee80211_channel b43legacy_bg_chantable[] = {
CHANTAB_ENT(1, 2412),
CHANTAB_ENT(13, 2472),
CHANTAB_ENT(14, 2484),
};
-#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable)
+
+static struct ieee80211_supported_band b43legacy_band_2GHz_BPHY = {
+ .channels = b43legacy_bg_chantable,
+ .n_channels = ARRAY_SIZE(b43legacy_bg_chantable),
+ .bitrates = b43legacy_b_ratetable,
+ .n_bitrates = b43legacy_b_ratetable_size,
+};
+
+static struct ieee80211_supported_band b43legacy_band_2GHz_GPHY = {
+ .channels = b43legacy_bg_chantable,
+ .n_channels = ARRAY_SIZE(b43legacy_bg_chantable),
+ .bitrates = b43legacy_g_ratetable,
+ .n_bitrates = b43legacy_g_ratetable_size,
+};
static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev);
static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev);
{
b43legacy_jssi_write(dev, 0x7F7F7F7F);
b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
- b43legacy_read32(dev,
- B43legacy_MMIO_MACCMD)
- | (1 << 4));
+ b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
+ | B43legacy_MACCMD_BGNOISE);
B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
dev->phy.channel);
}
if (1/*FIXME: the last PSpoll frame was sent successfully */)
b43legacy_power_saving_ctl_bits(dev, -1, -1);
}
- dev->reg124_set_0x4 = 0;
if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
- dev->reg124_set_0x4 = 1;
+ dev->dfq_valid = 1;
}
static void handle_irq_atim_end(struct b43legacy_wldev *dev)
{
- if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
- return;
- b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
- b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
- | 0x4);
+ if (dev->dfq_valid) {
+ b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+ b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
+ | B43legacy_MACCMD_DFQ_VALID);
+ dev->dfq_valid = 0;
+ }
}
static void handle_irq_pmq(struct b43legacy_wldev *dev)
u16 ram_offset,
u16 shm_size_offset, u8 rate)
{
- int len;
- const u8 *data;
- B43legacy_WARN_ON(!dev->cached_beacon);
- len = min((size_t)dev->cached_beacon->len,
+ unsigned int i, len, variable_len;
+ const struct ieee80211_mgmt *bcn;
+ const u8 *ie;
+ bool tim_found = 0;
+
+ bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
+ len = min((size_t)dev->wl->current_beacon->len,
0x200 - sizeof(struct b43legacy_plcp_hdr6));
- data = (const u8 *)(dev->cached_beacon->data);
- b43legacy_write_template_common(dev, data,
- len, ram_offset,
+
+ b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset,
shm_size_offset, rate);
+
+ /* Find the position of the TIM and the DTIM_period value
+ * and write them to SHM. */
+ ie = bcn->u.beacon.variable;
+ variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ for (i = 0; i < variable_len - 2; ) {
+ uint8_t ie_id, ie_len;
+
+ ie_id = ie[i];
+ ie_len = ie[i + 1];
+ if (ie_id == 5) {
+ u16 tim_position;
+ u16 dtim_period;
+ /* This is the TIM Information Element */
+
+ /* Check whether the ie_len is in the beacon data range. */
+ if (variable_len < ie_len + 2 + i)
+ break;
+ /* A valid TIM is at least 4 bytes long. */
+ if (ie_len < 4)
+ break;
+ tim_found = 1;
+
+ tim_position = sizeof(struct b43legacy_plcp_hdr6);
+ tim_position += offsetof(struct ieee80211_mgmt,
+ u.beacon.variable);
+ tim_position += i;
+
+ dtim_period = ie[i + 3];
+
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_TIMPOS, tim_position);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_DTIMP, dtim_period);
+ break;
+ }
+ i += ie_len + 2;
+ }
+ if (!tim_found) {
+ b43legacywarn(dev->wl, "Did not find a valid TIM IE in the "
+ "beacon template packet. AP or IBSS operation "
+ "may be broken.\n");
+ }
}
static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
u16 shm_offset, u16 size,
- u8 rate)
+ struct ieee80211_rate *rate)
{
struct b43legacy_plcp_hdr4 plcp;
u32 tmp;
__le16 dur;
plcp.data = 0;
- b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate);
dur = ieee80211_generic_frame_duration(dev->wl->hw,
dev->wl->vif,
size,
- B43legacy_RATE_TO_100KBPS(rate));
+ rate);
/* Write PLCP in two parts and timing for packet transfer */
tmp = le32_to_cpu(plcp.data);
b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset,
* 2) Patching duration field
* 3) Stripping TIM
*/
-static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
- u16 *dest_size, u8 rate)
+static const u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
+ u16 *dest_size,
+ struct ieee80211_rate *rate)
{
const u8 *src_data;
u8 *dest_data;
- u16 src_size;
- u16 elem_size;
- u16 src_pos;
- u16 dest_pos;
+ u16 src_size, elem_size, src_pos, dest_pos;
__le16 dur;
struct ieee80211_hdr *hdr;
+ size_t ie_start;
+
+ src_size = dev->wl->current_beacon->len;
+ src_data = (const u8 *)dev->wl->current_beacon->data;
- B43legacy_WARN_ON(!dev->cached_beacon);
- src_size = dev->cached_beacon->len;
- src_data = (const u8 *)dev->cached_beacon->data;
+ /* Get the start offset of the variable IEs in the packet. */
+ ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ B43legacy_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt,
+ u.beacon.variable));
- if (unlikely(src_size < 0x24)) {
- b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: "
- "invalid beacon\n");
+ if (B43legacy_WARN_ON(src_size < ie_start))
return NULL;
- }
dest_data = kmalloc(src_size, GFP_ATOMIC);
if (unlikely(!dest_data))
return NULL;
- /* 0x24 is offset of first variable-len Information-Element
- * in beacon frame.
- */
- memcpy(dest_data, src_data, 0x24);
- src_pos = 0x24;
- dest_pos = 0x24;
- for (; src_pos < src_size - 2; src_pos += elem_size) {
+ /* Copy the static data and all Information Elements, except the TIM. */
+ memcpy(dest_data, src_data, ie_start);
+ src_pos = ie_start;
+ dest_pos = ie_start;
+ for ( ; src_pos < src_size - 2; src_pos += elem_size) {
elem_size = src_data[src_pos + 1] + 2;
- if (src_data[src_pos] != 0x05) { /* TIM */
- memcpy(dest_data + dest_pos, src_data + src_pos,
- elem_size);
- dest_pos += elem_size;
+ if (src_data[src_pos] == 5) {
+ /* This is the TIM. */
+ continue;
}
+ memcpy(dest_data + dest_pos, src_data + src_pos, elem_size);
+ dest_pos += elem_size;
}
*dest_size = dest_pos;
hdr = (struct ieee80211_hdr *)dest_data;
dur = ieee80211_generic_frame_duration(dev->wl->hw,
dev->wl->vif,
*dest_size,
- B43legacy_RATE_TO_100KBPS(rate));
+ rate);
hdr->duration_id = dur;
return dest_data;
static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
u16 ram_offset,
- u16 shm_size_offset, u8 rate)
+ u16 shm_size_offset,
+ struct ieee80211_rate *rate)
{
- u8 *probe_resp_data;
+ const u8 *probe_resp_data;
u16 size;
- B43legacy_WARN_ON(!dev->cached_beacon);
- size = dev->cached_beacon->len;
+ size = dev->wl->current_beacon->len;
probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate);
if (unlikely(!probe_resp_data))
return;
* all possible basic rates
*/
b43legacy_write_probe_resp_plcp(dev, 0x31A, size,
- B43legacy_CCK_RATE_1MB);
+ &b43legacy_b_ratetable[0]);
b43legacy_write_probe_resp_plcp(dev, 0x32C, size,
- B43legacy_CCK_RATE_2MB);
+ &b43legacy_b_ratetable[1]);
b43legacy_write_probe_resp_plcp(dev, 0x33E, size,
- B43legacy_CCK_RATE_5MB);
+ &b43legacy_b_ratetable[2]);
b43legacy_write_probe_resp_plcp(dev, 0x350, size,
- B43legacy_CCK_RATE_11MB);
+ &b43legacy_b_ratetable[3]);
size = min((size_t)size,
0x200 - sizeof(struct b43legacy_plcp_hdr6));
b43legacy_write_template_common(dev, probe_resp_data,
size, ram_offset,
- shm_size_offset, rate);
+ shm_size_offset, rate->bitrate);
kfree(probe_resp_data);
}
-static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev,
- struct sk_buff *beacon)
-{
- if (dev->cached_beacon)
- kfree_skb(dev->cached_beacon);
- dev->cached_beacon = beacon;
-
- return 0;
-}
-
-static void b43legacy_update_templates(struct b43legacy_wldev *dev)
-{
- u32 status;
-
- B43legacy_WARN_ON(!dev->cached_beacon);
-
- b43legacy_write_beacon_template(dev, 0x68, 0x18,
- B43legacy_CCK_RATE_1MB);
- b43legacy_write_beacon_template(dev, 0x468, 0x1A,
- B43legacy_CCK_RATE_1MB);
- b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
- B43legacy_CCK_RATE_11MB);
-
- status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
- status |= 0x03;
- b43legacy_write32(dev, B43legacy_MMIO_MACCMD, status);
-}
-
-static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
- struct sk_buff *beacon)
+/* Asynchronously update the packet templates in template RAM.
+ * Locking: Requires wl->irq_lock to be locked. */
+static void b43legacy_update_templates(struct b43legacy_wl *wl,
+ struct sk_buff *beacon)
{
- int err;
+ /* This is the top half of the ansynchronous beacon update. The bottom
+ * half is the beacon IRQ. Beacon update must be asynchronous to avoid
+ * sending an invalid beacon. This can happen for example, if the
+ * firmware transmits a beacon while we are updating it. */
- err = b43legacy_refresh_cached_beacon(dev, beacon);
- if (unlikely(err))
- return;
- b43legacy_update_templates(dev);
+ if (wl->current_beacon)
+ dev_kfree_skb_any(wl->current_beacon);
+ wl->current_beacon = beacon;
+ wl->beacon0_uploaded = 0;
+ wl->beacon1_uploaded = 0;
}
static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
static void handle_irq_beacon(struct b43legacy_wldev *dev)
{
- u32 status;
+ struct b43legacy_wl *wl = dev->wl;
+ u32 cmd;
- if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ if (!b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
return;
- dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
- status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
-
- if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
- /* ACK beacon IRQ. */
- b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
- B43legacy_IRQ_BEACON);
- dev->irq_savedstate |= B43legacy_IRQ_BEACON;
- if (dev->cached_beacon)
- kfree_skb(dev->cached_beacon);
- dev->cached_beacon = NULL;
- return;
- }
- if (!(status & 0x1)) {
- b43legacy_write_beacon_template(dev, 0x68, 0x18,
- B43legacy_CCK_RATE_1MB);
- status |= 0x1;
- b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
- status);
- }
- if (!(status & 0x2)) {
- b43legacy_write_beacon_template(dev, 0x468, 0x1A,
- B43legacy_CCK_RATE_1MB);
- status |= 0x2;
- b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
- status);
+ /* This is the bottom half of the asynchronous beacon update. */
+
+ cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
+ if (!(cmd & B43legacy_MACCMD_BEACON0_VALID)) {
+ if (!wl->beacon0_uploaded) {
+ b43legacy_write_beacon_template(dev, 0x68,
+ B43legacy_SHM_SH_BTL0,
+ B43legacy_CCK_RATE_1MB);
+ b43legacy_write_probe_resp_template(dev, 0x268,
+ B43legacy_SHM_SH_PRTLEN,
+ &__b43legacy_ratetable[3]);
+ wl->beacon0_uploaded = 1;
+ }
+ cmd |= B43legacy_MACCMD_BEACON0_VALID;
+ }
+ if (!(cmd & B43legacy_MACCMD_BEACON1_VALID)) {
+ if (!wl->beacon1_uploaded) {
+ b43legacy_write_beacon_template(dev, 0x468,
+ B43legacy_SHM_SH_BTL1,
+ B43legacy_CCK_RATE_1MB);
+ wl->beacon1_uploaded = 1;
+ }
+ cmd |= B43legacy_MACCMD_BEACON1_VALID;
}
+ b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
}
static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ phy = &dev->phy;
/* Switch the PHY mode (if necessary). */
- switch (conf->phymode) {
- case MODE_IEEE80211B:
- new_phymode = B43legacy_PHYMODE_B;
- break;
- case MODE_IEEE80211G:
- new_phymode = B43legacy_PHYMODE_G;
+ switch (conf->channel->band) {
+ case IEEE80211_BAND_2GHZ:
+ if (phy->type == B43legacy_PHYTYPE_B)
+ new_phymode = B43legacy_PHYMODE_B;
+ else
+ new_phymode = B43legacy_PHYMODE_G;
break;
default:
B43legacy_WARN_ON(1);
err = b43legacy_switch_phymode(wl, new_phymode);
if (err)
goto out_unlock_mutex;
- dev = wl->current_dev;
- phy = &dev->phy;
/* Disable IRQs while reconfiguring the device.
* This makes it possible to drop the spinlock throughout
/* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */
- if (conf->channel_val != phy->channel)
- b43legacy_radio_selectchannel(dev, conf->channel_val, 0);
+ if (conf->channel->hw_value != phy->channel)
+ b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0);
/* Enable/Disable ShortSlot timing. */
if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
if (conf->beacon)
- b43legacy_refresh_templates(dev, conf->beacon);
+ b43legacy_update_templates(wl, conf->beacon);
}
b43legacy_write_mac_bssid_templates(dev);
}
static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
{
/* Flags */
- dev->reg124_set_0x4 = 0;
+ dev->dfq_valid = 0;
/* Stats */
memset(&dev->stats, 0, sizeof(dev->stats));
kfree(phy->tssi2dbm);
kfree(phy->lo_control);
phy->lo_control = NULL;
+ if (dev->wl->current_beacon) {
+ dev_kfree_skb_any(dev->wl->current_beacon);
+ dev->wl->current_beacon = NULL;
+ }
+
ssb_device_disable(dev->dev, 0);
ssb_bus_may_powerdown(dev->dev->bus);
}
return err;
}
+static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
+ int aid, int set)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct sk_buff *beacon;
+ unsigned long flags;
+
+ /* We could modify the existing beacon and set the aid bit in the TIM
+ * field, but that would probably require resizing and moving of data
+ * within the beacon template. Simply request a new beacon and let
+ * mac80211 do the hard work. */
+ beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
+ if (unlikely(!beacon))
+ return -ENOMEM;
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_update_templates(wl, beacon);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return 0;
+}
+
+static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
+ struct sk_buff *beacon,
+ struct ieee80211_tx_control *ctl)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_update_templates(wl, beacon);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return 0;
+}
+
static const struct ieee80211_ops b43legacy_hw_ops = {
.tx = b43legacy_op_tx,
.conf_tx = b43legacy_op_conf_tx,
.start = b43legacy_op_start,
.stop = b43legacy_op_stop,
.set_retry_limit = b43legacy_op_set_retry_limit,
+ .set_tim = b43legacy_op_beacon_set_tim,
+ .beacon_update = b43legacy_op_ibss_beacon_update,
};
/* Hard-reset the chip. Do not call this directly.
int have_gphy)
{
struct ieee80211_hw *hw = dev->wl->hw;
- struct ieee80211_hw_mode *mode;
struct b43legacy_phy *phy = &dev->phy;
- int cnt = 0;
- int err;
phy->possible_phymodes = 0;
- for (; 1; cnt++) {
- if (have_bphy) {
- B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
- mode = &phy->hwmodes[cnt];
-
- mode->mode = MODE_IEEE80211B;
- mode->num_channels = b43legacy_bg_chantable_size;
- mode->channels = b43legacy_bg_chantable;
- mode->num_rates = b43legacy_b_ratetable_size;
- mode->rates = b43legacy_b_ratetable;
- err = ieee80211_register_hwmode(hw, mode);
- if (err)
- return err;
-
- phy->possible_phymodes |= B43legacy_PHYMODE_B;
- have_bphy = 0;
- continue;
- }
- if (have_gphy) {
- B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
- mode = &phy->hwmodes[cnt];
-
- mode->mode = MODE_IEEE80211G;
- mode->num_channels = b43legacy_bg_chantable_size;
- mode->channels = b43legacy_bg_chantable;
- mode->num_rates = b43legacy_g_ratetable_size;
- mode->rates = b43legacy_g_ratetable;
- err = ieee80211_register_hwmode(hw, mode);
- if (err)
- return err;
-
- phy->possible_phymodes |= B43legacy_PHYMODE_G;
- have_gphy = 0;
- continue;
- }
- break;
+ if (have_bphy) {
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &b43legacy_band_2GHz_BPHY;
+ phy->possible_phymodes |= B43legacy_PHYMODE_B;
+ }
+
+ if (have_gphy) {
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &b43legacy_band_2GHz_GPHY;
+ phy->possible_phymodes |= B43legacy_PHYMODE_G;
}
return 0;
/* Extract the bitrate out of a CCK PLCP header. */
-static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp)
+static u8 b43legacy_plcp_get_bitrate_idx_cck(struct b43legacy_plcp_hdr6 *plcp)
{
switch (plcp->raw[0]) {
case 0x0A:
- return B43legacy_CCK_RATE_1MB;
+ return 0;
case 0x14:
- return B43legacy_CCK_RATE_2MB;
+ return 1;
case 0x37:
- return B43legacy_CCK_RATE_5MB;
+ return 2;
case 0x6E:
- return B43legacy_CCK_RATE_11MB;
+ return 3;
}
B43legacy_BUG_ON(1);
- return 0;
+ return -1;
}
/* Extract the bitrate out of an OFDM PLCP header. */
-static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp)
+static u8 b43legacy_plcp_get_bitrate_idx_ofdm(struct b43legacy_plcp_hdr6 *plcp,
+ bool aphy)
{
+ int base = aphy ? 0 : 4;
+
switch (plcp->raw[0] & 0xF) {
case 0xB:
- return B43legacy_OFDM_RATE_6MB;
+ return base + 0;
case 0xF:
- return B43legacy_OFDM_RATE_9MB;
+ return base + 1;
case 0xA:
- return B43legacy_OFDM_RATE_12MB;
+ return base + 2;
case 0xE:
- return B43legacy_OFDM_RATE_18MB;
+ return base + 3;
case 0x9:
- return B43legacy_OFDM_RATE_24MB;
+ return base + 4;
case 0xD:
- return B43legacy_OFDM_RATE_36MB;
+ return base + 5;
case 0x8:
- return B43legacy_OFDM_RATE_48MB;
+ return base + 6;
case 0xC:
- return B43legacy_OFDM_RATE_54MB;
+ return base + 7;
}
B43legacy_BUG_ON(1);
- return 0;
+ return -1;
}
u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate)
int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
u16 fctl;
u8 rate;
- u8 rate_fb;
+ struct ieee80211_rate *rate_fb;
int rate_ofdm;
int rate_fb_ofdm;
unsigned int plcp_fragment_len;
memset(txhdr, 0, sizeof(*txhdr));
- rate = txctl->tx_rate;
+ rate = txctl->tx_rate->hw_value;
rate_ofdm = b43legacy_is_ofdm_rate(rate);
- rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
- rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb);
+ rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate;
+ rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value);
txhdr->mac_frame_ctl = wlhdr->frame_control;
memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
/* Calculate duration for fallback rate */
- if ((rate_fb == rate) ||
+ if ((rate_fb->hw_value == rate) ||
(wlhdr->duration_id & cpu_to_le16(0x8000)) ||
(wlhdr->duration_id == cpu_to_le16(0))) {
/* If the fallback rate equals the normal rate or the
* use the original dur_id field. */
txhdr->dur_fb = wlhdr->duration_id;
} else {
- int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb);
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
txctl->vif,
fragment_len,
- fbrate_base100kbps);
+ rate_fb);
}
plcp_fragment_len = fragment_len + FCS_LEN;
rate);
b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
(&txhdr->plcp_fb), plcp_fragment_len,
- rate_fb);
+ rate_fb->hw_value);
/* PHY TX Control word */
if (rate_ofdm)
int rts_rate_ofdm;
int rts_rate_fb_ofdm;
- rts_rate = txctl->rts_cts_rate;
+ rts_rate = txctl->rts_cts_rate->hw_value;
rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
(phystat3 & B43legacy_RX_PHYST3_TRSTATE));
status.noise = dev->stats.link_noise;
status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
+ /* change to support A PHY */
if (phystat0 & B43legacy_RX_PHYST0_OFDM)
- status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp);
+ status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false);
else
- status.rate = b43legacy_plcp_get_bitrate_cck(plcp);
+ status.rate_idx = b43legacy_plcp_get_bitrate_idx_cck(plcp);
status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
/*
- * If monitors are present get full 64-bit timestamp. This
- * code assumes we get to process the packet within 16 bits
- * of timestamp, i.e. about 65 milliseconds after the PHY
- * received the first symbol.
+ * All frames on monitor interfaces and beacons always need a full
+ * 64-bit timestamp. Monitor interfaces need it for diagnostic
+ * purposes and beacons for IBSS merging.
+ * This code assumes we get to process the packet within 16 bits
+ * of timestamp, i.e. about 65 milliseconds after the PHY received
+ * the first symbol.
*/
- if (dev->wl->radiotap_enabled) {
+ if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
+ == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
+ dev->wl->radiotap_enabled) {
u16 low_mactime_now;
b43legacy_tsf_read(dev, &status.mactime);
B43legacy_RX_CHAN_ID_SHIFT;
switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) {
case B43legacy_PHYTYPE_B:
- status.phymode = MODE_IEEE80211B;
- status.freq = chanid + 2400;
- status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
- break;
case B43legacy_PHYTYPE_G:
- status.phymode = MODE_IEEE80211G;
+ status.band = IEEE80211_BAND_2GHZ;
status.freq = chanid + 2400;
- status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
break;
default:
b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
+++ /dev/null
-config BCM43XX
- tristate "Broadcom BCM43xx wireless support (DEPRECATED)"
- depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && WLAN_80211 && (!SSB_B43_PCI_BRIDGE || SSB != y) && EXPERIMENTAL
- select WIRELESS_EXT
- select FW_LOADER
- select HW_RANDOM
- ---help---
- This is an experimental driver for the Broadcom 43xx wireless
- chip, found in the Apple Airport Extreme and various other
- devices. This driver is deprecated and will be removed
- from the kernel in the near future. It has been replaced
- by the b43 and b43legacy drivers.
-
-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
- depends on BCM43XX
-
-config BCM43XX_PIO
- bool
- depends on BCM43XX
-
-choice
- prompt "BCM43xx data transfer mode"
- depends on BCM43XX
- default BCM43XX_DMA_AND_PIO_MODE
-
-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).
-
- 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
+++ /dev/null
-obj-$(CONFIG_BCM43XX) += bcm43xx.o
-bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.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_leds.o bcm43xx_ethtool.o \
- bcm43xx_xmit.o bcm43xx_sysfs.o \
- $(bcm43xx-obj-y)
+++ /dev/null
-#ifndef BCM43xx_H_
-#define BCM43xx_H_
-
-#include <linux/hw_random.h>
-#include <linux/version.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/stringify.h>
-#include <linux/pci.h>
-#include <net/ieee80211.h>
-#include <net/ieee80211softmac.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-
-
-#include "bcm43xx_debugfs.h"
-#include "bcm43xx_leds.h"
-
-
-#define PFX KBUILD_MODNAME ": "
-
-#define BCM43xx_SWITCH_CORE_MAX_RETRIES 50
-#define BCM43xx_IRQWAIT_MAX_RETRIES 100
-
-#define BCM43xx_IO_SIZE 8192
-
-/* 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_DMA0_REASON 0x20
-#define BCM43xx_MMIO_DMA0_IRQ_MASK 0x24
-#define BCM43xx_MMIO_DMA1_REASON 0x28
-#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x2C
-#define BCM43xx_MMIO_DMA2_REASON 0x30
-#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x34
-#define BCM43xx_MMIO_DMA3_REASON 0x38
-#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x3C
-#define BCM43xx_MMIO_DMA4_REASON 0x40
-#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x44
-#define BCM43xx_MMIO_DMA5_REASON 0x48
-#define BCM43xx_MMIO_DMA5_IRQ_MASK 0x4C
-#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 */
-
-/* 32-bit DMA */
-#define BCM43xx_MMIO_DMA32_BASE0 0x200
-#define BCM43xx_MMIO_DMA32_BASE1 0x220
-#define BCM43xx_MMIO_DMA32_BASE2 0x240
-#define BCM43xx_MMIO_DMA32_BASE3 0x260
-#define BCM43xx_MMIO_DMA32_BASE4 0x280
-#define BCM43xx_MMIO_DMA32_BASE5 0x2A0
-/* 64-bit DMA */
-#define BCM43xx_MMIO_DMA64_BASE0 0x200
-#define BCM43xx_MMIO_DMA64_BASE1 0x240
-#define BCM43xx_MMIO_DMA64_BASE2 0x280
-#define BCM43xx_MMIO_DMA64_BASE3 0x2C0
-#define BCM43xx_MMIO_DMA64_BASE4 0x300
-#define BCM43xx_MMIO_DMA64_BASE5 0x340
-/* PIO */
-#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_RNG 0x65A
-#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 */
-#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
-
-/* 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_CTL 0x28
-#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
-#define BCM43xx_SBTOPCI2_MEMREAD_MULTI 0x20
-
-/* PCI-E core registers. */
-#define BCM43xx_PCIECORE_REG_ADDR 0x0130
-#define BCM43xx_PCIECORE_REG_DATA 0x0134
-#define BCM43xx_PCIECORE_MDIO_CTL 0x0128
-#define BCM43xx_PCIECORE_MDIO_DATA 0x012C
-
-/* PCI-E registers. */
-#define BCM43xx_PCIE_TLP_WORKAROUND 0x0004
-#define BCM43xx_PCIE_DLLP_LINKCTL 0x0100
-
-/* PCI-E MDIO bits. */
-#define BCM43xx_PCIE_MDIO_ST 0x40000000
-#define BCM43xx_PCIE_MDIO_WT 0x10000000
-#define BCM43xx_PCIE_MDIO_DEV 22
-#define BCM43xx_PCIE_MDIO_REG 18
-#define BCM43xx_PCIE_MDIO_TA 0x00020000
-#define BCM43xx_PCIE_MDIO_TC 0x0100
-
-/* MDIO devices. */
-#define BCM43xx_MDIO_SERDES_RX 0x1F
-
-/* SERDES RX registers. */
-#define BCM43xx_SERDES_RXTIMER 0x2
-#define BCM43xx_SERDES_CDR 0x6
-#define BCM43xx_SERDES_CDR_BW 0x7
-
-/* 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
-#define BCM43xx_COREID_PCIE 0x820
-
-/* 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
-#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE 0x20000000
-
-/* sbtmstatehigh state flags */
-#define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001
-#define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004
-#define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020
-#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000
-#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL 0x00020000
-#define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
-#define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000
-#define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000
-#define BCM43xx_SBTMSTATEHIGH_BISTFAILED 0x40000000
-#define BCM43xx_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000
-
-/* 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_MODE_G 0x80000000
-
-/* Microcode */
-#define BCM43xx_UCODE_REVISION 0x0000
-#define BCM43xx_UCODE_PATCHLEVEL 0x0002
-#define BCM43xx_UCODE_DATE 0x0004
-#define BCM43xx_UCODE_TIME 0x0006
-#define BCM43xx_UCODE_STATUS 0x0040
-
-/* 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
-
-/* Hardware Radio Enable masks */
-#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
-#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
-
-/* 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
-
-/* 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
-
-/* FIXME: the next line is a guess as to what the maximum RSSI value might be */
-#define RX_RSSI_MAX 60
-
-/* 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 bcm43xx_dmaring;
-struct bcm43xx_pioqueue;
-
-struct bcm43xx_initval {
- __be16 offset;
- __be16 size;
- __be32 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 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 analog;
- 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;
-
- /* 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()
- */
- spinlock_t lock;
-
- /* Firmware. */
- const struct firmware *ucode;
- const struct firmware *pcm;
- const struct firmware *initvals0;
- const struct firmware *initvals1;
-};
-
-
-struct bcm43xx_radioinfo {
- u16 manufact;
- u16 version;
- u8 revision;
-
- /* 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.
- * 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;
- /* 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 *tx_ring4;
- struct bcm43xx_dmaring *tx_ring5;
-
- struct bcm43xx_dmaring *rx_ring0;
- struct bcm43xx_dmaring *rx_ring3; /* 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
-
-/* Generic information about a core. */
-struct bcm43xx_coreinfo {
- u8 available:1,
- enabled:1,
- initialized:1;
- /** core_rev revision number */
- u8 rev;
- /** Index number for _switch_core() */
- u8 index;
- /** core_id ID number */
- u16 id;
- /** Core-specific data. */
- void *priv;
-};
-
-/* 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). */
-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 noise;
- struct iw_statistics wstats;
- /* 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;
-};
-
-/* Driver initialization status. */
-enum {
- BCM43xx_STAT_UNINIT, /* Uninitialized. */
- BCM43xx_STAT_INITIALIZING, /* init_board() in progress. */
- BCM43xx_STAT_INITIALIZED, /* Fully operational. */
- BCM43xx_STAT_SHUTTINGDOWN, /* free_board() in progress. */
- BCM43xx_STAT_RESTARTING, /* controller_restart() called. */
-};
-#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
-#define bcm43xx_set_status(bcm, stat) do { \
- atomic_set(&(bcm)->init_status, (stat)); \
- smp_wmb(); \
- } while (0)
-
-/* *** THEORY OF LOCKING ***
- *
- * We have two different locks in the bcm43xx driver.
- * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
- * and the device registers. This mutex does _not_ protect
- * against concurrency from the IRQ handler.
- * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
- *
- * Please note that, if you only take the irq_lock, you are not protected
- * against concurrency from the periodic work handlers.
- * Most times you want to take _both_ locks.
- */
-
-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;
-
- spinlock_t irq_lock;
- struct mutex mutex;
-
- /* Driver initialization status BCM43xx_STAT_*** */
- atomic_t init_status;
-
- u16 was_initialized:1, /* for PCI suspend/resume. */
- __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. */
- short_preamble:1, /* TRUE, if short preamble is enabled. */
- firmware_norelease:1, /* Do not release the firmware. Used on suspend. */
- radio_hw_enable:1; /* TRUE if radio is hardware enabled */
-
- struct bcm43xx_stats stats;
-
- /* Bus type we are connected to.
- * This is currently always BCM43xx_BUSTYPE_PCI
- */
- u8 bustype;
- u64 dma_mask;
-
- u16 board_vendor;
- u16 board_type;
- u16 board_revision;
-
- u16 chip_id;
- u8 chip_rev;
- u8 chip_package;
-
- struct bcm43xx_sprominfo sprom;
-#define BCM43xx_NR_LEDS 4
- struct bcm43xx_led leds[BCM43xx_NR_LEDS];
- spinlock_t leds_lock;
-
- /* The currently active core. */
- struct bcm43xx_coreinfo *current_core;
- 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_80211[ BCM43xx_MAX_80211_CORES ];
- /* Additional information, specific to the 80211 cores. */
- struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
- /* Number of available 80211 cores. */
- int nr_80211_available;
-
- u32 chipcommon_capabilities;
-
- /* Reason code of the last interrupt. */
- u32 irq_reason;
- u32 dma_reason[6];
- /* saved irq enable/disable state bitfield. */
- u32 irq_savedstate;
- /* Link Quality calculation context. */
- struct bcm43xx_noise_calculation noisecalc;
- /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
- int mac_suspended;
-
- /* 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;
-
- /* Periodic tasks */
- struct delayed_work periodic_work;
- unsigned int periodic_state;
-
- 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;
-
- /* Random Number Generator. */
- struct hwrng rng;
- char rng_name[20 + 1];
-
- /* Debugging stuff follows. */
-#ifdef CONFIG_BCM43XX_DEBUG
- struct bcm43xx_dfsentry *dfsentry;
-#endif
-};
-
-
-static inline
-struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
-{
- return ieee80211softmac_priv(dev);
-}
-
-struct device;
-
-static inline
-struct bcm43xx_private * dev_to_bcm(struct device *dev)
-{
- struct net_device *net_dev;
- struct bcm43xx_private *bcm;
-
- net_dev = dev_get_drvdata(dev);
- bcm = bcm43xx_priv(net_dev);
-
- return bcm;
-}
-
-
-/* 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
-
-/* 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
-struct bcm43xx_coreinfo_80211 *
-bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
-{
- assert(bcm->current_core->id == BCM43xx_COREID_80211);
- return bcm->current_core->priv;
-}
-static inline
-struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
-{
- assert(bcm43xx_using_pio(bcm));
- return &(bcm43xx_current_80211_priv(bcm)->pio);
-}
-static inline
-struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
-{
- assert(!bcm43xx_using_pio(bcm));
- return &(bcm43xx_current_80211_priv(bcm)->dma);
-}
-static inline
-struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
-{
- return &(bcm43xx_current_80211_priv(bcm)->phy);
-}
-static inline
-struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
-{
- return &(bcm43xx_current_80211_priv(bcm)->radio);
-}
-
-
-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));
-}
-
-
-static inline
-u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
-{
- return ioread16(bcm->mmio_addr + offset);
-}
-
-static inline
-void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
-{
- iowrite16(value, bcm->mmio_addr + offset);
-}
-
-static inline
-u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
-{
- return ioread32(bcm->mmio_addr + offset);
-}
-
-static inline
-void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
-{
- iowrite32(value, bcm->mmio_addr + offset);
-}
-
-static inline
-int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- return pci_write_config_dword(bcm->pci_dev, offset, value);
-}
-
-/** 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; \
- })
-
-#endif /* BCM43xx_H_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- debugfs driver debugging code
-
- Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
-
- 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 <linux/fs.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include "bcm43xx.h"
-#include "bcm43xx_main.h"
-#include "bcm43xx_debugfs.h"
-#include "bcm43xx_dma.h"
-#include "bcm43xx_pio.h"
-#include "bcm43xx_xmit.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->i_private;
- 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);
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (bcm43xx_status(bcm) != BCM43xx_STAT_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\n", bcm->mmio_addr);
- 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).available \
- ? "available" : "nonavailable", \
- (info).enabled \
- ? "enabled" : "disabled", \
- (info).id, (info).rev, (info).index)
- fappend_core("CHIPCOMMON", bcm->core_chipcommon);
- fappend_core("PCI", bcm->core_pci);
- 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->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
- 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(KBUILD_MODNAME " driver\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);
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (bcm43xx_status(bcm) != BCM43xx_STAT_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->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
- 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);
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (bcm43xx_status(bcm) != BCM43xx_STAT_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->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
- 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;
- unsigned long long 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;
- }
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (bcm43xx_status(bcm) != BCM43xx_STAT_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);
- mmiowb();
- res = buf_size;
-
-out_unlock:
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-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);
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_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->irq_lock, flags);
- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (*ppos == pos) {
- /* Done. Drop the copied data. */
- e->xmitstatus_printing = 0;
- }
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
- up(&big_buffer_sem);
- return res;
-}
-
-static ssize_t restart_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;
-
- 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;
- }
- mutex_lock(&(bcm)->mutex);
- spin_lock_irqsave(&(bcm)->irq_lock, flags);
- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
- printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
- res = -EFAULT;
- goto out_unlock;
- }
- if (count > 0 && buf[0] == '1') {
- bcm43xx_controller_restart(bcm, "manually restarted");
- res = count;
- } else
- res = -EINVAL;
-
-out_unlock:
- spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
- mutex_unlock(&(bcm)->mutex);
-out_up:
- up(&big_buffer_sem);
- return res;
-}
-
-#undef fappend
-
-
-static const struct file_operations devinfo_fops = {
- .read = devinfo_read_file,
- .write = write_file_dummy,
- .open = open_file_generic,
-};
-
-static const struct file_operations spromdump_fops = {
- .read = spromdump_read_file,
- .write = write_file_dummy,
- .open = open_file_generic,
-};
-
-static const struct file_operations drvinfo_fops = {
- .read = drvinfo_read_file,
- .write = write_file_dummy,
- .open = open_file_generic,
-};
-
-static const struct file_operations tsf_fops = {
- .read = tsf_read_file,
- .write = tsf_write_file,
- .open = open_file_generic,
-};
-
-static const struct file_operations txstat_fops = {
- .read = txstat_read_file,
- .write = write_file_dummy,
- .open = open_file_generic,
-};
-
-static const struct file_operations restart_fops = {
- .write = restart_write_file,
- .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);
- e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
- bcm, &restart_fops);
- if (!e->dentry_restart)
- printk(KERN_ERR PFX "debugfs: creating \"restart\" 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->dentry_restart);
- 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(KBUILD_MODNAME, NULL);
- if (!fs.root)
- 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 \"" KBUILD_MODNAME "/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, %zd bytes):",
- description, size);
- for (i = 0; i < size; i++) {
- c = data[i];
- if (i % 8 == 0)
- printk("\n" KERN_INFO PFX "0x%08zx: 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, %zd 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%08zx: ", 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");
-}
+++ /dev/null
-#ifndef BCM43xx_DEBUGFS_H_
-#define BCM43xx_DEBUGFS_H_
-
-struct bcm43xx_private;
-struct bcm43xx_xmitstatus;
-
-#ifdef CONFIG_BCM43XX_DEBUG
-
-#include <linux/list.h>
-#include <asm/semaphore.h>
-
-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 dentry *dentry_restart;
-
- 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_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- DMA ringbuffer and descriptor allocation/management
-
- Copyright (c) 2005, 2006 Michael Buesch <mbuesch@freenet.de>
-
- 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 "bcm43xx_xmit.h"
-
-#include <linux/dma-mapping.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-
-
-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);
- }
- }
-}
-
-u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
-{
- static const u16 map64[] = {
- BCM43xx_MMIO_DMA64_BASE0,
- BCM43xx_MMIO_DMA64_BASE1,
- BCM43xx_MMIO_DMA64_BASE2,
- BCM43xx_MMIO_DMA64_BASE3,
- BCM43xx_MMIO_DMA64_BASE4,
- BCM43xx_MMIO_DMA64_BASE5,
- };
- static const u16 map32[] = {
- BCM43xx_MMIO_DMA32_BASE0,
- BCM43xx_MMIO_DMA32_BASE1,
- BCM43xx_MMIO_DMA32_BASE2,
- BCM43xx_MMIO_DMA32_BASE3,
- BCM43xx_MMIO_DMA32_BASE4,
- BCM43xx_MMIO_DMA32_BASE5,
- };
-
- if (dma64bit) {
- assert(controller_idx >= 0 &&
- controller_idx < ARRAY_SIZE(map64));
- return map64[controller_idx];
- }
- assert(controller_idx >= 0 &&
- controller_idx < ARRAY_SIZE(map32));
- return map32[controller_idx];
-}
-
-static inline
-dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
- unsigned char *buf,
- size_t len,
- int tx)
-{
- dma_addr_t dmaaddr;
- int direction = PCI_DMA_FROMDEVICE;
-
- if (tx)
- direction = PCI_DMA_TODEVICE;
-
- dmaaddr = pci_map_single(ring->bcm->pci_dev,
- buf, len,
- direction);
-
- return dmaaddr;
-}
-
-static inline
-void unmap_descbuffer(struct bcm43xx_dmaring *ring,
- dma_addr_t addr,
- size_t len,
- int tx)
-{
- if (tx) {
- pci_unmap_single(ring->bcm->pci_dev,
- addr, len,
- PCI_DMA_TODEVICE);
- } else {
- pci_unmap_single(ring->bcm->pci_dev,
- addr, len,
- PCI_DMA_FROMDEVICE);
- }
-}
-
-static inline
-void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
- dma_addr_t addr,
- size_t len)
-{
- assert(!ring->tx);
-
- pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
- addr, len, PCI_DMA_FROMDEVICE);
-}
-
-static inline
-void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
- dma_addr_t addr,
- size_t len)
-{
- assert(!ring->tx);
-
- pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
- addr, len, PCI_DMA_TODEVICE);
-}
-
-/* Unmap and free a descriptor buffer. */
-static inline
-void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
- struct bcm43xx_dmadesc_meta *meta,
- int irq_context)
-{
- assert(meta->skb);
- if (irq_context)
- dev_kfree_skb_irq(meta->skb);
- else
- dev_kfree_skb(meta->skb);
- meta->skb = NULL;
-}
-
-static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
-{
- ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
- &(ring->dmabase));
- if (!ring->descbase) {
- /* Allocation may have failed due to pci_alloc_consistent
- insisting on use of GFP_DMA, which is more restrictive
- than necessary... */
- struct dma_desc *rx_ring;
- dma_addr_t rx_ring_dma;
-
- rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
- if (!rx_ring)
- goto out_err;
-
- rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
- BCM43xx_DMA_RINGMEMSIZE,
- PCI_DMA_BIDIRECTIONAL);
-
- if (pci_dma_mapping_error(rx_ring_dma) ||
- rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
- /* Sigh... */
- if (!pci_dma_mapping_error(rx_ring_dma))
- pci_unmap_single(ring->bcm->pci_dev,
- rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
- PCI_DMA_BIDIRECTIONAL);
- rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
- rx_ring, BCM43xx_DMA_RINGMEMSIZE,
- PCI_DMA_BIDIRECTIONAL);
- if (pci_dma_mapping_error(rx_ring_dma) ||
- rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
- assert(0);
- if (!pci_dma_mapping_error(rx_ring_dma))
- pci_unmap_single(ring->bcm->pci_dev,
- rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
- PCI_DMA_BIDIRECTIONAL);
- goto out_err;
- }
- }
-
- ring->descbase = rx_ring;
- ring->dmabase = rx_ring_dma;
- }
- memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
-
- return 0;
-out_err:
- printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
- return -ENOMEM;
-}
-
-static void free_ringmemory(struct bcm43xx_dmaring *ring)
-{
- struct device *dev = &(ring->bcm->pci_dev->dev);
-
- dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
- ring->descbase, ring->dmabase);
-}
-
-/* Reset the RX DMA channel */
-int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
- u16 mmio_base, int dma64)
-{
- int i;
- u32 value;
- u16 offset;
-
- offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
- bcm43xx_write32(bcm, mmio_base + offset, 0);
- for (i = 0; i < 1000; i++) {
- offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS;
- value = bcm43xx_read32(bcm, mmio_base + offset);
- if (dma64) {
- value &= BCM43xx_DMA64_RXSTAT;
- if (value == BCM43xx_DMA64_RXSTAT_DISABLED) {
- i = -1;
- break;
- }
- } else {
- value &= BCM43xx_DMA32_RXSTATE;
- if (value == BCM43xx_DMA32_RXSTAT_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;
-}
-
-/* Reset the RX DMA channel */
-int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
- u16 mmio_base, int dma64)
-{
- int i;
- u32 value;
- u16 offset;
-
- for (i = 0; i < 1000; i++) {
- offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
- value = bcm43xx_read32(bcm, mmio_base + offset);
- if (dma64) {
- value &= BCM43xx_DMA64_TXSTAT;
- if (value == BCM43xx_DMA64_TXSTAT_DISABLED ||
- value == BCM43xx_DMA64_TXSTAT_IDLEWAIT ||
- value == BCM43xx_DMA64_TXSTAT_STOPPED)
- break;
- } else {
- value &= BCM43xx_DMA32_TXSTATE;
- if (value == BCM43xx_DMA32_TXSTAT_DISABLED ||
- value == BCM43xx_DMA32_TXSTAT_IDLEWAIT ||
- value == BCM43xx_DMA32_TXSTAT_STOPPED)
- break;
- }
- udelay(10);
- }
- offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
- bcm43xx_write32(bcm, mmio_base + offset, 0);
- for (i = 0; i < 1000; i++) {
- offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
- value = bcm43xx_read32(bcm, mmio_base + offset);
- if (dma64) {
- value &= BCM43xx_DMA64_TXSTAT;
- if (value == BCM43xx_DMA64_TXSTAT_DISABLED) {
- i = -1;
- break;
- }
- } else {
- value &= BCM43xx_DMA32_TXSTATE;
- if (value == BCM43xx_DMA32_TXSTAT_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 void fill_descriptor(struct bcm43xx_dmaring *ring,
- struct bcm43xx_dmadesc_generic *desc,
- dma_addr_t dmaaddr,
- u16 bufsize,
- int start, int end, int irq)
-{
- int slot;
-
- slot = bcm43xx_dma_desc2idx(ring, desc);
- assert(slot >= 0 && slot < ring->nr_slots);
-
- if (ring->dma64) {
- u32 ctl0 = 0, ctl1 = 0;
- u32 addrlo, addrhi;
- u32 addrext;
-
- addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
- addrhi = (((u64)dmaaddr >> 32) & ~BCM43xx_DMA64_ROUTING);
- addrext = (((u64)dmaaddr >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
- addrhi |= ring->routing;
- if (slot == ring->nr_slots - 1)
- ctl0 |= BCM43xx_DMA64_DCTL0_DTABLEEND;
- if (start)
- ctl0 |= BCM43xx_DMA64_DCTL0_FRAMESTART;
- if (end)
- ctl0 |= BCM43xx_DMA64_DCTL0_FRAMEEND;
- if (irq)
- ctl0 |= BCM43xx_DMA64_DCTL0_IRQ;
- ctl1 |= (bufsize - ring->frameoffset)
- & BCM43xx_DMA64_DCTL1_BYTECNT;
- ctl1 |= (addrext << BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT)
- & BCM43xx_DMA64_DCTL1_ADDREXT_MASK;
-
- desc->dma64.control0 = cpu_to_le32(ctl0);
- desc->dma64.control1 = cpu_to_le32(ctl1);
- desc->dma64.address_low = cpu_to_le32(addrlo);
- desc->dma64.address_high = cpu_to_le32(addrhi);
- } else {
- u32 ctl;
- u32 addr;
- u32 addrext;
-
- addr = (u32)(dmaaddr & ~BCM43xx_DMA32_ROUTING);
- addrext = (u32)(dmaaddr & BCM43xx_DMA32_ROUTING)
- >> BCM43xx_DMA32_ROUTING_SHIFT;
- addr |= ring->routing;
- ctl = (bufsize - ring->frameoffset)
- & BCM43xx_DMA32_DCTL_BYTECNT;
- if (slot == ring->nr_slots - 1)
- ctl |= BCM43xx_DMA32_DCTL_DTABLEEND;
- if (start)
- ctl |= BCM43xx_DMA32_DCTL_FRAMESTART;
- if (end)
- ctl |= BCM43xx_DMA32_DCTL_FRAMEEND;
- if (irq)
- ctl |= BCM43xx_DMA32_DCTL_IRQ;
- ctl |= (addrext << BCM43xx_DMA32_DCTL_ADDREXT_SHIFT)
- & BCM43xx_DMA32_DCTL_ADDREXT_MASK;
-
- desc->dma32.control = cpu_to_le32(ctl);
- desc->dma32.address = cpu_to_le32(addr);
- }
-}
-
-static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
- struct bcm43xx_dmadesc_generic *desc,
- struct bcm43xx_dmadesc_meta *meta,
- gfp_t gfp_flags)
-{
- struct bcm43xx_rxhdr *rxhdr;
- struct bcm43xx_hwxmitstatus *xmitstat;
- dma_addr_t dmaaddr;
- struct sk_buff *skb;
-
- 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);
- /* This hardware bug work-around adapted from the b44 driver.
- The chip may be unable to do PCI DMA to/from anything above 1GB */
- if (pci_dma_mapping_error(dmaaddr) ||
- dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
- /* This one has 30-bit addressing... */
- if (!pci_dma_mapping_error(dmaaddr))
- pci_unmap_single(ring->bcm->pci_dev,
- dmaaddr, ring->rx_buffersize,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb_any(skb);
- skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
- if (skb == NULL)
- return -ENOMEM;
- dmaaddr = pci_map_single(ring->bcm->pci_dev,
- skb->data, ring->rx_buffersize,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(dmaaddr) ||
- dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
- assert(0);
- dev_kfree_skb_any(skb);
- return -ENOMEM;
- }
- }
- meta->skb = skb;
- meta->dmaaddr = dmaaddr;
- skb->dev = ring->bcm->net_dev;
-
- fill_descriptor(ring, desc, dmaaddr,
- ring->rx_buffersize, 0, 0, 0);
-
- rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
- rxhdr->frame_length = 0;
- rxhdr->flags1 = 0;
- xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data);
- xmitstat->cookie = 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_generic *desc;
- struct bcm43xx_dmadesc_meta *meta;
-
- for (i = 0; i < ring->nr_slots; i++) {
- desc = bcm43xx_dma_idx2desc(ring, i, &meta);
-
- err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
- if (err)
- goto err_unwind;
- }
- mb();
- ring->used_slots = ring->nr_slots;
- err = 0;
-out:
- return err;
-
-err_unwind:
- for (i--; i >= 0; i--) {
- desc = bcm43xx_dma_idx2desc(ring, i, &meta);
-
- unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
- dev_kfree_skb(meta->skb);
- }
- 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;
- u32 addrext;
-
- if (ring->tx) {
- if (ring->dma64) {
- u64 ringbase = (u64)(ring->dmabase);
-
- addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
- value = BCM43xx_DMA64_TXENABLE;
- value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT)
- & BCM43xx_DMA64_TXADDREXT_MASK;
- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value);
- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO,
- (ringbase & 0xFFFFFFFF));
- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI,
- ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
- | ring->routing);
- } else {
- u32 ringbase = (u32)(ring->dmabase);
-
- addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
- value = BCM43xx_DMA32_TXENABLE;
- value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT)
- & BCM43xx_DMA32_TXADDREXT_MASK;
- bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value);
- bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING,
- (ringbase & ~BCM43xx_DMA32_ROUTING)
- | ring->routing);
- }
- } else {
- err = alloc_initial_descbuffers(ring);
- if (err)
- goto out;
- if (ring->dma64) {
- u64 ringbase = (u64)(ring->dmabase);
-
- addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
- value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT);
- value |= BCM43xx_DMA64_RXENABLE;
- value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT)
- & BCM43xx_DMA64_RXADDREXT_MASK;
- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value);
- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO,
- (ringbase & 0xFFFFFFFF));
- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI,
- ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
- | ring->routing);
- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200);
- } else {
- u32 ringbase = (u32)(ring->dmabase);
-
- addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
- value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT);
- value |= BCM43xx_DMA32_RXENABLE;
- value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT)
- & BCM43xx_DMA32_RXADDREXT_MASK;
- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value);
- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING,
- (ringbase & ~BCM43xx_DMA32_ROUTING)
- | ring->routing);
- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200);
- }
- }
-
-out:
- return err;
-}
-
-/* Shutdown the DMA controller. */
-static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
-{
- if (ring->tx) {
- bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64);
- if (ring->dma64) {
- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0);
- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0);
- } else
- bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0);
- } else {
- bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64);
- if (ring->dma64) {
- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0);
- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0);
- } else
- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0);
- }
-}
-
-static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
-{
- struct bcm43xx_dmadesc_generic *desc;
- struct bcm43xx_dmadesc_meta *meta;
- int i;
-
- if (!ring->used_slots)
- return;
- for (i = 0; i < ring->nr_slots; i++) {
- desc = bcm43xx_dma_idx2desc(ring, i, &meta);
-
- if (!meta->skb) {
- assert(ring->tx);
- 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, meta, 0);
- }
-}
-
-/* Main initialization function. */
-static
-struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
- int controller_index,
- int for_tx,
- int dma64)
-{
- struct bcm43xx_dmaring *ring;
- int err;
- int nr_slots;
-
- ring = kzalloc(sizeof(*ring), GFP_KERNEL);
- if (!ring)
- goto out;
-
- nr_slots = BCM43xx_RXRING_SLOTS;
- if (for_tx)
- nr_slots = BCM43xx_TXRING_SLOTS;
-
- ring->meta = kcalloc(nr_slots, sizeof(struct bcm43xx_dmadesc_meta),
- GFP_KERNEL);
- if (!ring->meta)
- goto err_kfree_ring;
-
- ring->routing = BCM43xx_DMA32_CLIENTTRANS;
- if (dma64)
- ring->routing = BCM43xx_DMA64_CLIENTTRANS;
-
- ring->bcm = bcm;
- ring->nr_slots = nr_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 = bcm43xx_dmacontroller_base(dma64, controller_index);
- ring->index = controller_index;
- ring->dma64 = !!dma64;
- if (for_tx) {
- ring->tx = 1;
- ring->current_slot = -1;
- } else {
- if (ring->index == 0) {
- ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE;
- ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET;
- } else if (ring->index == 3) {
- ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE;
- ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET;
- } else
- assert(0);
- }
-
- err = alloc_ringmemory(ring);
- if (err)
- goto err_kfree_meta;
- err = dmacontroller_setup(ring);
- if (err)
- goto err_free_ringmemory;
- return ring;
-
-out:
- printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
- 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-%s 0x%04X (%s) max used slots: %d/%d\n",
- (ring->dma64) ? "64" : "32",
- 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)
-{
- struct bcm43xx_dma *dma;
-
- if (bcm43xx_using_pio(bcm))
- return;
- dma = bcm43xx_current_dma(bcm);
-
- bcm43xx_destroy_dmaring(dma->rx_ring3);
- dma->rx_ring3 = NULL;
- bcm43xx_destroy_dmaring(dma->rx_ring0);
- dma->rx_ring0 = NULL;
-
- bcm43xx_destroy_dmaring(dma->tx_ring5);
- dma->tx_ring5 = NULL;
- bcm43xx_destroy_dmaring(dma->tx_ring4);
- dma->tx_ring4 = 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 = bcm43xx_current_dma(bcm);
- struct bcm43xx_dmaring *ring;
- int err = -ENOMEM;
- int dma64 = 0;
-
- bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
- if (bcm->dma_mask == DMA_64BIT_MASK)
- dma64 = 1;
- err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
- if (err)
- goto no_dma;
- err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
- if (err)
- goto no_dma;
-
- /* setup TX DMA channels. */
- ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
- if (!ring)
- goto out;
- dma->tx_ring0 = ring;
-
- ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64);
- if (!ring)
- goto err_destroy_tx0;
- dma->tx_ring1 = ring;
-
- ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64);
- if (!ring)
- goto err_destroy_tx1;
- dma->tx_ring2 = ring;
-
- ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64);
- if (!ring)
- goto err_destroy_tx2;
- dma->tx_ring3 = ring;
-
- ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64);
- if (!ring)
- goto err_destroy_tx3;
- dma->tx_ring4 = ring;
-
- ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64);
- if (!ring)
- goto err_destroy_tx4;
- dma->tx_ring5 = ring;
-
- /* setup RX DMA channels. */
- ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64);
- if (!ring)
- goto err_destroy_tx5;
- dma->rx_ring0 = ring;
-
- if (bcm->current_core->rev < 5) {
- ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64);
- if (!ring)
- goto err_destroy_rx0;
- dma->rx_ring3 = ring;
- }
-
- dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
- (bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
- (bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
- err = 0;
-out:
- return err;
-
-err_destroy_rx0:
- bcm43xx_destroy_dmaring(dma->rx_ring0);
- dma->rx_ring0 = NULL;
-err_destroy_tx5:
- bcm43xx_destroy_dmaring(dma->tx_ring5);
- dma->tx_ring5 = NULL;
-err_destroy_tx4:
- bcm43xx_destroy_dmaring(dma->tx_ring4);
- dma->tx_ring4 = NULL;
-err_destroy_tx3:
- bcm43xx_destroy_dmaring(dma->tx_ring3);
- dma->tx_ring3 = NULL;
-err_destroy_tx2:
- bcm43xx_destroy_dmaring(dma->tx_ring2);
- dma->tx_ring2 = NULL;
-err_destroy_tx1:
- bcm43xx_destroy_dmaring(dma->tx_ring1);
- dma->tx_ring1 = NULL;
-err_destroy_tx0:
- bcm43xx_destroy_dmaring(dma->tx_ring0);
- dma->tx_ring0 = NULL;
-no_dma:
-#ifdef CONFIG_BCM43XX_PIO
- printk(KERN_WARNING PFX "DMA not supported on this device."
- " Falling back to PIO.\n");
- bcm->__using_pio = 1;
- return -ENOSYS;
-#else
- printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
- "Please recompile the driver with PIO support.\n");
- return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
-}
-
-/* Generate a cookie for the TX header. */
-static u16 generate_cookie(struct bcm43xx_dmaring *ring,
- int slot)
-{
- u16 cookie = 0x1000;
-
- /* Use the upper 4 bits of the cookie as
- * DMA controller ID and store the slot number
- * in the lower 12 bits.
- * Note that the cookie must never be 0, as this
- * is a special value used in RX path.
- */
- switch (ring->index) {
- case 0:
- cookie = 0xA000;
- break;
- case 1:
- cookie = 0xB000;
- break;
- case 2:
- cookie = 0xC000;
- break;
- case 3:
- cookie = 0xD000;
- break;
- case 4:
- cookie = 0xE000;
- break;
- case 5:
- cookie = 0xF000;
- break;
- }
- assert(((u16)slot & 0xF000) == 0x0000);
- cookie |= (u16)slot;
-
- return cookie;
-}
-
-/* Inspect a cookie and find out to which controller/slot it belongs. */
-static
-struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
- u16 cookie, int *slot)
-{
- struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
- struct bcm43xx_dmaring *ring = NULL;
-
- switch (cookie & 0xF000) {
- case 0xA000:
- ring = dma->tx_ring0;
- break;
- case 0xB000:
- ring = dma->tx_ring1;
- break;
- case 0xC000:
- ring = dma->tx_ring2;
- break;
- case 0xD000:
- ring = dma->tx_ring3;
- break;
- case 0xE000:
- ring = dma->tx_ring4;
- break;
- case 0xF000:
- ring = dma->tx_ring5;
- break;
- default:
- assert(0);
- }
- *slot = (cookie & 0x0FFF);
- assert(*slot >= 0 && *slot < ring->nr_slots);
-
- return ring;
-}
-
-static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
- int slot)
-{
- u16 offset;
- int descsize;
-
- /* 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);
- offset = (ring->dma64) ? BCM43xx_DMA64_TXINDEX : BCM43xx_DMA32_TXINDEX;
- descsize = (ring->dma64) ? sizeof(struct bcm43xx_dmadesc64)
- : sizeof(struct bcm43xx_dmadesc32);
- bcm43xx_dma_write(ring, offset,
- (u32)(slot * descsize));
-}
-
-static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
- struct sk_buff *skb,
- u8 cur_frag)
-{
- int slot;
- struct bcm43xx_dmadesc_generic *desc;
- struct bcm43xx_dmadesc_meta *meta;
- dma_addr_t dmaaddr;
- struct sk_buff *bounce_skb;
-
- assert(skb_shinfo(skb)->nr_frags == 0);
-
- slot = request_slot(ring);
- desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
-
- /* 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));
- dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
- if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
- /* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */
- if (!dma_mapping_error(dmaaddr))
- unmap_descbuffer(ring, dmaaddr, skb->len, 1);
- bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
- if (!bounce_skb)
- return;
- dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1);
- if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
- if (!dma_mapping_error(dmaaddr))
- unmap_descbuffer(ring, dmaaddr, skb->len, 1);
- dev_kfree_skb_any(bounce_skb);
- assert(0);
- return;
- }
- skb_copy_from_linear_data(skb, skb_put(bounce_skb, skb->len),
- skb->len);
- dev_kfree_skb_any(skb);
- skb = bounce_skb;
- }
-
- meta->skb = skb;
- meta->dmaaddr = dmaaddr;
-
- fill_descriptor(ring, desc, dmaaddr,
- skb->len, 1, 1, 1);
-
- /* Now transfer the whole frame. */
- dmacontroller_poke_tx(ring, slot);
-}
-
-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 = bcm43xx_current_dma(bcm)->tx_ring1;
- 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;
- }
-
- for (i = 0; i < txb->nr_frags; i++) {
- skb = txb->fragments[i];
- /* Take skb from ieee80211_txb_free */
- txb->fragments[i] = NULL;
- dma_tx_fragment(ring, skb, i);
- }
- ieee80211_txb_free(txb);
-
- return 0;
-}
-
-void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
- struct bcm43xx_xmitstatus *status)
-{
- struct bcm43xx_dmaring *ring;
- struct bcm43xx_dmadesc_generic *desc;
- struct bcm43xx_dmadesc_meta *meta;
- int is_last_fragment;
- int slot;
- u32 tmp;
-
- ring = parse_cookie(bcm, status->cookie, &slot);
- assert(ring);
- assert(ring->tx);
- while (1) {
- assert(slot >= 0 && slot < ring->nr_slots);
- desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
-
- if (ring->dma64) {
- tmp = le32_to_cpu(desc->dma64.control0);
- is_last_fragment = !!(tmp & BCM43xx_DMA64_DCTL0_FRAMEEND);
- } else {
- tmp = le32_to_cpu(desc->dma32.control);
- is_last_fragment = !!(tmp & BCM43xx_DMA32_DCTL_FRAMEEND);
- }
- unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
- free_descriptor_buffer(ring, 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;
-}
-
-static void dma_rx(struct bcm43xx_dmaring *ring,
- int *slot)
-{
- struct bcm43xx_dmadesc_generic *desc;
- struct bcm43xx_dmadesc_meta *meta;
- struct bcm43xx_rxhdr *rxhdr;
- struct sk_buff *skb;
- u16 len;
- int err;
- dma_addr_t dmaaddr;
-
- desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
-
- sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
- skb = meta->skb;
-
- if (ring->index == 3) {
- /* We received an xmit status. */
- struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
- struct bcm43xx_xmitstatus stat;
- int i = 0;
-
- stat.cookie = le16_to_cpu(hw->cookie);
- while (stat.cookie == 0) {
- if (unlikely(++i >= 10000)) {
- assert(0);
- break;
- }
- udelay(2);
- barrier();
- 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 (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
- * 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 = 0;
- s32 tmp = len;
-
- while (1) {
- desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
- /* 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 "
- "(len: %u, buffer: %u, nr-dropped: %d)\n",
- len, ring->rx_buffersize, 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");
- sync_descbuffer_for_device(ring, dmaaddr,
- ring->rx_buffersize);
- 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 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);
- if (ring->dma64) {
- status = bcm43xx_dma_read(ring, BCM43xx_DMA64_RXSTATUS);
- descptr = (status & BCM43xx_DMA64_RXSTATDPTR);
- current_slot = descptr / sizeof(struct bcm43xx_dmadesc64);
- } else {
- status = bcm43xx_dma_read(ring, BCM43xx_DMA32_RXSTATUS);
- descptr = (status & BCM43xx_DMA32_RXDPTR);
- current_slot = descptr / sizeof(struct bcm43xx_dmadesc32);
- }
- 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
- }
- if (ring->dma64) {
- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX,
- (u32)(slot * sizeof(struct bcm43xx_dmadesc64)));
- } else {
- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX,
- (u32)(slot * sizeof(struct bcm43xx_dmadesc32)));
- }
- 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);
- if (ring->dma64) {
- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
- bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
- | BCM43xx_DMA64_TXSUSPEND);
- } else {
- bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
- bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
- | BCM43xx_DMA32_TXSUSPEND);
- }
-}
-
-void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
-{
- assert(ring->tx);
- if (ring->dma64) {
- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
- bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
- & ~BCM43xx_DMA64_TXSUSPEND);
- } else {
- bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
- bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
- & ~BCM43xx_DMA32_TXSUSPEND);
- }
- bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
-}
+++ /dev/null
-#ifndef BCM43xx_DMA_H_
-#define BCM43xx_DMA_H_
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/dma-mapping.h>
-#include <linux/linkage.h>
-#include <asm/atomic.h>
-
-
-/* DMA-Interrupt reasons. */
-#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)
-
-
-/*** 32-bit DMA Engine. ***/
-
-/* 32-bit DMA controller registers. */
-#define BCM43xx_DMA32_TXCTL 0x00
-#define BCM43xx_DMA32_TXENABLE 0x00000001
-#define BCM43xx_DMA32_TXSUSPEND 0x00000002
-#define BCM43xx_DMA32_TXLOOPBACK 0x00000004
-#define BCM43xx_DMA32_TXFLUSH 0x00000010
-#define BCM43xx_DMA32_TXADDREXT_MASK 0x00030000
-#define BCM43xx_DMA32_TXADDREXT_SHIFT 16
-#define BCM43xx_DMA32_TXRING 0x04
-#define BCM43xx_DMA32_TXINDEX 0x08
-#define BCM43xx_DMA32_TXSTATUS 0x0C
-#define BCM43xx_DMA32_TXDPTR 0x00000FFF
-#define BCM43xx_DMA32_TXSTATE 0x0000F000
-#define BCM43xx_DMA32_TXSTAT_DISABLED 0x00000000
-#define BCM43xx_DMA32_TXSTAT_ACTIVE 0x00001000
-#define BCM43xx_DMA32_TXSTAT_IDLEWAIT 0x00002000
-#define BCM43xx_DMA32_TXSTAT_STOPPED 0x00003000
-#define BCM43xx_DMA32_TXSTAT_SUSP 0x00004000
-#define BCM43xx_DMA32_TXERROR 0x000F0000
-#define BCM43xx_DMA32_TXERR_NOERR 0x00000000
-#define BCM43xx_DMA32_TXERR_PROT 0x00010000
-#define BCM43xx_DMA32_TXERR_UNDERRUN 0x00020000
-#define BCM43xx_DMA32_TXERR_BUFREAD 0x00030000
-#define BCM43xx_DMA32_TXERR_DESCREAD 0x00040000
-#define BCM43xx_DMA32_TXACTIVE 0xFFF00000
-#define BCM43xx_DMA32_RXCTL 0x10
-#define BCM43xx_DMA32_RXENABLE 0x00000001
-#define BCM43xx_DMA32_RXFROFF_MASK 0x000000FE
-#define BCM43xx_DMA32_RXFROFF_SHIFT 1
-#define BCM43xx_DMA32_RXDIRECTFIFO 0x00000100
-#define BCM43xx_DMA32_RXADDREXT_MASK 0x00030000
-#define BCM43xx_DMA32_RXADDREXT_SHIFT 16
-#define BCM43xx_DMA32_RXRING 0x14
-#define BCM43xx_DMA32_RXINDEX 0x18
-#define BCM43xx_DMA32_RXSTATUS 0x1C
-#define BCM43xx_DMA32_RXDPTR 0x00000FFF
-#define BCM43xx_DMA32_RXSTATE 0x0000F000
-#define BCM43xx_DMA32_RXSTAT_DISABLED 0x00000000
-#define BCM43xx_DMA32_RXSTAT_ACTIVE 0x00001000
-#define BCM43xx_DMA32_RXSTAT_IDLEWAIT 0x00002000
-#define BCM43xx_DMA32_RXSTAT_STOPPED 0x00003000
-#define BCM43xx_DMA32_RXERROR 0x000F0000
-#define BCM43xx_DMA32_RXERR_NOERR 0x00000000
-#define BCM43xx_DMA32_RXERR_PROT 0x00010000
-#define BCM43xx_DMA32_RXERR_OVERFLOW 0x00020000
-#define BCM43xx_DMA32_RXERR_BUFWRITE 0x00030000
-#define BCM43xx_DMA32_RXERR_DESCREAD 0x00040000
-#define BCM43xx_DMA32_RXACTIVE 0xFFF00000
-
-/* 32-bit DMA descriptor. */
-struct bcm43xx_dmadesc32 {
- __le32 control;
- __le32 address;
-} __attribute__((__packed__));
-#define BCM43xx_DMA32_DCTL_BYTECNT 0x00001FFF
-#define BCM43xx_DMA32_DCTL_ADDREXT_MASK 0x00030000
-#define BCM43xx_DMA32_DCTL_ADDREXT_SHIFT 16
-#define BCM43xx_DMA32_DCTL_DTABLEEND 0x10000000
-#define BCM43xx_DMA32_DCTL_IRQ 0x20000000
-#define BCM43xx_DMA32_DCTL_FRAMEEND 0x40000000
-#define BCM43xx_DMA32_DCTL_FRAMESTART 0x80000000
-
-/* Address field Routing value. */
-#define BCM43xx_DMA32_ROUTING 0xC0000000
-#define BCM43xx_DMA32_ROUTING_SHIFT 30
-#define BCM43xx_DMA32_NOTRANS 0x00000000
-#define BCM43xx_DMA32_CLIENTTRANS 0x40000000
-
-
-
-/*** 64-bit DMA Engine. ***/
-
-/* 64-bit DMA controller registers. */
-#define BCM43xx_DMA64_TXCTL 0x00
-#define BCM43xx_DMA64_TXENABLE 0x00000001
-#define BCM43xx_DMA64_TXSUSPEND 0x00000002
-#define BCM43xx_DMA64_TXLOOPBACK 0x00000004
-#define BCM43xx_DMA64_TXFLUSH 0x00000010
-#define BCM43xx_DMA64_TXADDREXT_MASK 0x00030000
-#define BCM43xx_DMA64_TXADDREXT_SHIFT 16
-#define BCM43xx_DMA64_TXINDEX 0x04
-#define BCM43xx_DMA64_TXRINGLO 0x08
-#define BCM43xx_DMA64_TXRINGHI 0x0C
-#define BCM43xx_DMA64_TXSTATUS 0x10
-#define BCM43xx_DMA64_TXSTATDPTR 0x00001FFF
-#define BCM43xx_DMA64_TXSTAT 0xF0000000
-#define BCM43xx_DMA64_TXSTAT_DISABLED 0x00000000
-#define BCM43xx_DMA64_TXSTAT_ACTIVE 0x10000000
-#define BCM43xx_DMA64_TXSTAT_IDLEWAIT 0x20000000
-#define BCM43xx_DMA64_TXSTAT_STOPPED 0x30000000
-#define BCM43xx_DMA64_TXSTAT_SUSP 0x40000000
-#define BCM43xx_DMA64_TXERROR 0x14
-#define BCM43xx_DMA64_TXERRDPTR 0x0001FFFF
-#define BCM43xx_DMA64_TXERR 0xF0000000
-#define BCM43xx_DMA64_TXERR_NOERR 0x00000000
-#define BCM43xx_DMA64_TXERR_PROT 0x10000000
-#define BCM43xx_DMA64_TXERR_UNDERRUN 0x20000000
-#define BCM43xx_DMA64_TXERR_TRANSFER 0x30000000
-#define BCM43xx_DMA64_TXERR_DESCREAD 0x40000000
-#define BCM43xx_DMA64_TXERR_CORE 0x50000000
-#define BCM43xx_DMA64_RXCTL 0x20
-#define BCM43xx_DMA64_RXENABLE 0x00000001
-#define BCM43xx_DMA64_RXFROFF_MASK 0x000000FE
-#define BCM43xx_DMA64_RXFROFF_SHIFT 1
-#define BCM43xx_DMA64_RXDIRECTFIFO 0x00000100
-#define BCM43xx_DMA64_RXADDREXT_MASK 0x00030000
-#define BCM43xx_DMA64_RXADDREXT_SHIFT 16
-#define BCM43xx_DMA64_RXINDEX 0x24
-#define BCM43xx_DMA64_RXRINGLO 0x28
-#define BCM43xx_DMA64_RXRINGHI 0x2C
-#define BCM43xx_DMA64_RXSTATUS 0x30
-#define BCM43xx_DMA64_RXSTATDPTR 0x00001FFF
-#define BCM43xx_DMA64_RXSTAT 0xF0000000
-#define BCM43xx_DMA64_RXSTAT_DISABLED 0x00000000
-#define BCM43xx_DMA64_RXSTAT_ACTIVE 0x10000000
-#define BCM43xx_DMA64_RXSTAT_IDLEWAIT 0x20000000
-#define BCM43xx_DMA64_RXSTAT_STOPPED 0x30000000
-#define BCM43xx_DMA64_RXSTAT_SUSP 0x40000000
-#define BCM43xx_DMA64_RXERROR 0x34
-#define BCM43xx_DMA64_RXERRDPTR 0x0001FFFF
-#define BCM43xx_DMA64_RXERR 0xF0000000
-#define BCM43xx_DMA64_RXERR_NOERR 0x00000000
-#define BCM43xx_DMA64_RXERR_PROT 0x10000000
-#define BCM43xx_DMA64_RXERR_UNDERRUN 0x20000000
-#define BCM43xx_DMA64_RXERR_TRANSFER 0x30000000
-#define BCM43xx_DMA64_RXERR_DESCREAD 0x40000000
-#define BCM43xx_DMA64_RXERR_CORE 0x50000000
-
-/* 64-bit DMA descriptor. */
-struct bcm43xx_dmadesc64 {
- __le32 control0;
- __le32 control1;
- __le32 address_low;
- __le32 address_high;
-} __attribute__((__packed__));
-#define BCM43xx_DMA64_DCTL0_DTABLEEND 0x10000000
-#define BCM43xx_DMA64_DCTL0_IRQ 0x20000000
-#define BCM43xx_DMA64_DCTL0_FRAMEEND 0x40000000
-#define BCM43xx_DMA64_DCTL0_FRAMESTART 0x80000000
-#define BCM43xx_DMA64_DCTL1_BYTECNT 0x00001FFF
-#define BCM43xx_DMA64_DCTL1_ADDREXT_MASK 0x00030000
-#define BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT 16
-
-/* Address field Routing value. */
-#define BCM43xx_DMA64_ROUTING 0xC0000000
-#define BCM43xx_DMA64_ROUTING_SHIFT 30
-#define BCM43xx_DMA64_NOTRANS 0x00000000
-#define BCM43xx_DMA64_CLIENTTRANS 0x80000000
-
-
-
-struct bcm43xx_dmadesc_generic {
- union {
- struct bcm43xx_dmadesc32 dma32;
- struct bcm43xx_dmadesc64 dma64;
- } __attribute__((__packed__));
-} __attribute__((__packed__));
-
-
-/* Misc DMA constants */
-#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE
-#define BCM43xx_DMA0_RX_FRAMEOFFSET 30
-#define BCM43xx_DMA3_RX_FRAMEOFFSET 0
-
-
-/* DMA engine tuning knobs */
-#define BCM43xx_TXRING_SLOTS 512
-#define BCM43xx_RXRING_SLOTS 64
-#define BCM43xx_DMA0_RX_BUFFERSIZE (2304 + 100)
-#define BCM43xx_DMA3_RX_BUFFERSIZE 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
-
-
-
-#ifdef CONFIG_BCM43XX_DMA
-
-
-struct sk_buff;
-struct bcm43xx_private;
-struct bcm43xx_xmitstatus;
-
-
-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;
-};
-
-struct bcm43xx_dmaring {
- /* Kernel virtual base address of the ring memory. */
- void *descbase;
- /* Meta data about all descriptors. */
- struct bcm43xx_dmadesc_meta *meta;
- /* DMA Routing value. */
- u32 routing;
- /* (Unadjusted) DMA base bus-address of the ring memory. */
- dma_addr_t dmabase;
- /* 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. */
- u16 mmio_base;
- /* DMA controller index number (0-5). */
- int index;
- /* Boolean. Is this a TX ring? */
- u8 tx;
- /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
- u8 dma64;
- /* Boolean. Are transfers suspended on this ring? */
- u8 suspended;
- struct bcm43xx_private *bcm;
-#ifdef CONFIG_BCM43XX_DEBUG
- /* Maximum number of used slots. */
- int max_used_slots;
-#endif /* CONFIG_BCM43XX_DEBUG*/
-};
-
-
-static inline
-int bcm43xx_dma_desc2idx(struct bcm43xx_dmaring *ring,
- struct bcm43xx_dmadesc_generic *desc)
-{
- if (ring->dma64) {
- struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
- return (int)(&(desc->dma64) - dd64);
- } else {
- struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
- return (int)(&(desc->dma32) - dd32);
- }
-}
-
-static inline
-struct bcm43xx_dmadesc_generic * bcm43xx_dma_idx2desc(struct bcm43xx_dmaring *ring,
- int slot,
- struct bcm43xx_dmadesc_meta **meta)
-{
- *meta = &(ring->meta[slot]);
- if (ring->dma64) {
- struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
- return (struct bcm43xx_dmadesc_generic *)(&(dd64[slot]));
- } else {
- struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
- return (struct bcm43xx_dmadesc_generic *)(&(dd32[slot]));
- }
-}
-
-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);
-
-int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
- u16 dmacontroller_mmio_base,
- int dma64);
-int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
- u16 dmacontroller_mmio_base,
- int dma64);
-
-u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx);
-
-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);
-
-int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
- struct ieee80211_txb *txb);
-void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
-
-/* Helper function that returns the dma mask for this device. */
-static inline
-u64 bcm43xx_get_supported_dma_mask(struct bcm43xx_private *bcm)
-{
- int dma64 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH) &
- BCM43xx_SBTMSTATEHIGH_DMA64BIT;
- u16 mmio_base = bcm43xx_dmacontroller_base(dma64, 0);
- u32 mask = BCM43xx_DMA32_TXADDREXT_MASK;
-
- if (dma64)
- return DMA_64BIT_MASK;
- bcm43xx_write32(bcm, mmio_base + BCM43xx_DMA32_TXCTL, mask);
- if (bcm43xx_read32(bcm, mmio_base + BCM43xx_DMA32_TXCTL) & mask)
- return DMA_32BIT_MASK;
- return DMA_30BIT_MASK;
-}
-
-#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,
- int dma64)
-{
- return 0;
-}
-static inline
-int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
- u16 dmacontroller_mmio_base,
- int dma64)
-{
- 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)
-{
-}
-static inline
-void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
-{
-}
-static inline
-void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
-{
-}
-
-#endif /* CONFIG_BCM43XX_DMA */
-#endif /* BCM43xx_DMA_H_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- ethtool support
-
- Copyright (c) 2006 Jason Lunz <lunz@falooley.org>
-
- 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 <linux/netdevice.h>
-#include <linux/pci.h>
-#include <linux/string.h>
-#include <linux/utsname.h>
-
-
-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, utsname()->release, sizeof(info->version));
- strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
-}
-
-const struct ethtool_ops bcm43xx_ethtool_ops = {
- .get_drvinfo = bcm43xx_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
+++ /dev/null
-#ifndef BCM43xx_ETHTOOL_H_
-#define BCM43xx_ETHTOOL_H_
-
-#include <linux/ethtool.h>
-
-extern const struct ethtool_ops bcm43xx_ethtool_ops;
-
-#endif /* BCM43xx_ETHTOOL_H_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
-{
- 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);
- } else {
- bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
- mmiowb();
- bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val);
- }
-}
-
-void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val)
-{
- 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_DATA2, (val & 0xFFFF0000) >> 16);
- bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val & 0x0000FFFF);
- } else {
- bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
- mmiowb();
- bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (val & 0xFFFF0000) >> 16);
- bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val & 0x0000FFFF);
- }
-}
-
-u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset)
-{
- 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 {
- bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
- return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1);
- }
-}
+++ /dev/null
-#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_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
-void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val);
-u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset);
-
-#endif /* BCM43xx_ILT_H_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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_radio.h"
-#include "bcm43xx.h"
-
-#include <linux/bitops.h>
-
-
-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);
- ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
- 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->leds_lock, flags);
- if (led->blink_interval) {
- bcm43xx_led_changestate(led);
- mod_timer(&led->blink_timer, jiffies + led->blink_interval);
- }
- spin_unlock_irqrestore(&bcm->leds_lock, flags);
-}
-
-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;
- 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);
-}
-
-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;
- led->activelow = 1;
- 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;
- 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;
- setup_timer(&led->blink_timer,
- bcm43xx_led_blink,
- (unsigned long)led);
-
- if (sprom[i] == 0xFF) {
- bcm43xx_led_init_hardcoded(bcm, led, i);
- } 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_switch_all(bcm, 0);
-}
-
-void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
-{
- struct bcm43xx_led *led;
- 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;
- u16 ledctl;
- unsigned long flags;
-
- spin_lock_irqsave(&bcm->leds_lock, flags);
- ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
- for (i = 0; i < BCM43xx_NR_LEDS; i++) {
- led = &(bcm->leds[i]);
-
- turn_on = 0;
- switch (led->behaviour) {
- case BCM43xx_LED_INACTIVE:
- continue;
- case BCM43xx_LED_OFF:
- case BCM43xx_LED_BCM4303_3:
- break;
- case BCM43xx_LED_ON:
- turn_on = 1;
- break;
- case BCM43xx_LED_ACTIVITY:
- case BCM43xx_LED_BCM4303_0:
- turn_on = activity;
- break;
- case BCM43xx_LED_RADIO_ALL:
- turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
- break;
- case BCM43xx_LED_RADIO_A:
- case BCM43xx_LED_BCM4303_2:
- turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
- phy->type == BCM43xx_PHYTYPE_A);
- break;
- case BCM43xx_LED_RADIO_B:
- case BCM43xx_LED_BCM4303_1:
- turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
- (phy->type == BCM43xx_PHYTYPE_B ||
- phy->type == BCM43xx_PHYTYPE_G));
- break;
- case BCM43xx_LED_MODE_BG:
- if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
- 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
- break;
- case BCM43xx_LED_ASSOC:
- if (bcm->softmac->associnfo.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:
- dprintkl(KERN_INFO PFX "Bad value in leds_update,"
- " led->behaviour: 0x%x\n", led->behaviour);
- };
-
- 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);
- spin_unlock_irqrestore(&bcm->leds_lock, flags);
-}
-
-void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
-{
- struct bcm43xx_led *led;
- u16 ledctl;
- int i;
- int bit_on;
- unsigned long flags;
-
- spin_lock_irqsave(&bcm->leds_lock, flags);
- 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 (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);
- spin_unlock_irqrestore(&bcm->leds_lock, flags);
-}
+++ /dev/null
-#ifndef BCM43xx_LEDS_H_
-#define BCM43xx_LEDS_H_
-
-#include <linux/types.h>
-#include <linux/timer.h>
-
-
-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 / 1)
-#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,
-
- /* 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,
-
- /* Misc values for BCM4303 */
- BCM43xx_LED_BCM4303_0 = 0x2B,
- BCM43xx_LED_BCM4303_1 = 0x78,
- BCM43xx_LED_BCM4303_2 = 0x2E,
- BCM43xx_LED_BCM4303_3 = 0x19,
-};
-
-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_switch_all(struct bcm43xx_private *bcm, int on);
-
-#endif /* BCM43xx_LEDS_H_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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 <linux/delay.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/version.h>
-#include <linux/firmware.h>
-#include <linux/wireless.h>
-#include <linux/workqueue.h>
-#include <linux/skbuff.h>
-#include <linux/dma-mapping.h>
-#include <net/iw_handler.h>
-
-#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"
-#include "bcm43xx_ethtool.h"
-#include "bcm43xx_xmit.h"
-#include "bcm43xx_sysfs.h"
-
-
-MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
-MODULE_AUTHOR("Martin Langer");
-MODULE_AUTHOR("Stefano Brivio");
-MODULE_AUTHOR("Michael Buesch");
-MODULE_LICENSE("GPL");
-
-#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);
-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_noleds;
-module_param_named(noleds, modparam_noleds, int, 0444);
-MODULE_PARM_DESC(noleds, "Turn off all LED activity");
-
-static char modparam_fwpostfix[64];
-module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
-MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions.");
-
-
-/* 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
-
-
-/* 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 */
- { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- /* Broadcom 4311 802.11(a)/b/g */
- { PCI_VENDOR_ID_BROADCOM, 0x4311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- /* Broadcom 4312 802.11a/b/g */
- { PCI_VENDOR_ID_BROADCOM, 0x4312, 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 4319 802.11a/b/g */
- { PCI_VENDOR_ID_BROADCOM, 0x4319, 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 },
- { 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);
- mmiowb();
- 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);
- 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;
- }
- offset >>= 2;
- }
- bcm43xx_shm_control_word(bcm, routing, offset);
- mmiowb();
- 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);
- mmiowb();
- bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
- value);
- return;
- }
- offset >>= 2;
- }
- bcm43xx_shm_control_word(bcm, routing, offset);
- mmiowb();
- 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);
- mmiowb();
-
- /* 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;
-
- 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);
- u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
- u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
- u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
-
- 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);
- }
-
- status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
- status &= ~BCM43xx_SBF_TIME_UPDATE;
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
-}
-
-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 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)));
-}
-
-//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. */
- 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);
-}
-
-static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
-{
- bcm43xx_set_slot_time(bcm, 9);
-}
-
-static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
-{
- bcm43xx_set_slot_time(bcm, 20);
-}
-#endif
-
-/* 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);
- 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 (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G &&
- ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
- bcm43xx_short_slot_timing_enable(bcm);
-
- bcm43xx_mac_enable(bcm);
-}
-
-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);
-}
-#endif
-
-/* 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;
-}
-
-/* Synchronize IRQ top- and bottom-half.
- * IRQs must be masked before calling this.
- * This must not be called with the irq_lock held.
- */
-static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
-{
- synchronize_irq(bcm->irq);
- tasklet_disable(&bcm->isr_tasklet);
-}
-
-/* Make sure we don't receive more data from the device. */
-static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- return -EBUSY;
- }
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); /* flush */
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- bcm43xx_synchronize_irq(bcm);
-
- return 0;
-}
-
-static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- u32 radio_id;
- u16 manufact;
- u16 version;
- u8 revision;
-
- 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 (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;
- }
-
- radio->manufact = manufact;
- radio->version = version;
- radio->revision = revision;
-
- if (phy->type == BCM43xx_PHYTYPE_A)
- radio->txpower_desired = bcm->sprom.maxpower_aphy;
- else
- radio->txpower_desired = bcm->sprom.maxpower_bgphy;
-
- 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];
-}
-
-static 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;
-}
-
-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. */
- err = 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]);
- mmiowb();
- mdelay(20);
- }
- spromctl &= ~0x10; /* SPROM WRITE enable. */
- err = 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;
-
- sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
- GFP_KERNEL);
- if (!sprom) {
- printk(KERN_ERR PFX "sprom_extract OOM\n");
- return -ENOMEM;
- }
- bcm43xx_sprom_read(bcm, sprom);
-
- /* boardflags2 */
- value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
- bcm->sprom.boardflags2 = value;
-
- /* il0macaddr */
- value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
- *(((__be16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
- value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
- *(((__be16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
- value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
- *(((__be16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
-
- /* et0macaddr */
- value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
- *(((__be16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
- value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
- *(((__be16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
- value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
- *(((__be16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
-
- /* et1macaddr */
- value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
- *(((__be16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
- value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
- *(((__be16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
- value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
- *(((__be16 *)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;
-
- /* 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;
- /* 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];
- 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_geo_init(struct bcm43xx_private *bcm)
-{
- struct ieee80211_geo *geo;
- struct ieee80211_channel *chan;
- int have_a = 0, have_bg = 0;
- int i;
- u8 channel;
- struct bcm43xx_phyinfo *phy;
- const char *iso_country;
- u8 max_bg_channel;
-
- geo = kzalloc(sizeof(*geo), GFP_KERNEL);
- if (!geo)
- return -ENOMEM;
-
- 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:
- have_bg = 1;
- break;
- case BCM43xx_PHYTYPE_A:
- have_a = 1;
- break;
- default:
- assert(0);
- }
- }
- iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
-
-/* set the maximum channel based on locale set in sprom or witle locale option */
- switch (bcm->sprom.locale) {
- case BCM43xx_LOCALE_THAILAND:
- case BCM43xx_LOCALE_ISRAEL:
- case BCM43xx_LOCALE_JORDAN:
- case BCM43xx_LOCALE_USA_CANADA_ANZ:
- case BCM43xx_LOCALE_USA_LOW:
- max_bg_channel = 11;
- break;
- case BCM43xx_LOCALE_JAPAN:
- case BCM43xx_LOCALE_JAPAN_HIGH:
- max_bg_channel = 14;
- break;
- default:
- max_bg_channel = 13;
- }
-
- if (have_a) {
- for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL;
- channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) {
- chan = &geo->a[i++];
- chan->freq = bcm43xx_channel_to_freq_a(channel);
- chan->channel = channel;
- }
- geo->a_channels = i;
- }
- if (have_bg) {
- for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL;
- channel <= max_bg_channel; channel++) {
- chan = &geo->bg[i++];
- chan->freq = bcm43xx_channel_to_freq_bg(channel);
- chan->channel = channel;
- }
- 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);
- kfree(geo);
-
- return 0;
-}
-
-/* DummyTransmission function, as documented on
- * http://bcm-specs.sipsolutions.net/DummyTransmission
- */
-void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
-{
- 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] = {
- 0x00000000,
- 0x0000D400,
- 0x00000000,
- 0x00000001,
- 0x00000000,
- };
-
- switch (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, ((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);
-
- 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)
- break;
- udelay(10);
- }
- for (i = 0x00; i < 0x0A; i++) {
- value = bcm43xx_read16(bcm, 0x050E);
- if (value & 0x0400)
- break;
- udelay(10);
- }
- for (i = 0x00; i < 0x0A; i++) {
- value = bcm43xx_read16(bcm, 0x0690);
- 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,
- u8 index, u8 algorithm, const __le16 *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 = le16_to_cpu(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 __be32 *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,
- be32_to_cpu(*addr));
- bcm43xx_shm_write16(bcm,
- BCM43xx_SHM_HWMAC,
- (index * 2) + 1,
- be16_to_cpu(*((__be16 *)(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 __le16 *)key);
- keymac_write(bcm, index, (const __be32 *)mac_addr);
-
- bcm->key[index].algorithm = algorithm;
-
- return 0;
-}
-
-static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
-{
- static const __be32 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");
-}
-
-/* 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;
- u32 current_core;
-
- assert(core >= 0);
- while (1) {
- err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
- (core * 0x1000) + 0x18000000);
- 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);
- }
-
- 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 (unlikely(!new_core))
- return 0;
- if (!new_core->available)
- return -ENODEV;
- if (bcm->current_core == new_core)
- return 0;
- err = _switch_core(bcm, new_core->index);
- if (unlikely(err))
- goto out;
-
- bcm->current_core = new_core;
-out:
- return err;
-}
-
-static 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->enabled = 0;
-
- 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->enabled = 1;
- 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)) &&
- !bcm43xx_using_pio(bcm)) {
- }
- if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
- & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
- } else {
- if (connect_phy)
- flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
- 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. */
-static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm)
-{
- u32 sbtmstatelow;
-
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_radio_turn_off(bcm);
- sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow &= 0xDFF5FFFF;
- sbtmstatelow |= 0x000A0000;
- bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
- udelay(1);
- sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow &= 0xFFF5FFFF;
- sbtmstatelow |= 0x00080000;
- bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
- udelay(1);
-}
-
-static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
-{
- u32 v0, v1;
- u16 tmp;
- struct bcm43xx_xmitstatus stat;
-
- 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_AMPDU)
- continue;
- if (stat.flags & BCM43xx_TXSTAT_FLAG_INTER)
- continue;
-
- if (bcm43xx_using_pio(bcm))
- bcm43xx_pio_handle_xmitstatus(bcm, &stat);
- else
- bcm43xx_dma_handle_xmitstatus(bcm, &stat);
- }
-}
-
-static void drain_txstatus_queue(struct bcm43xx_private *bcm)
-{
- u32 dummy;
-
- if (bcm->current_core->rev < 5)
- return;
- /* Read all entries from the microcode TXstatus FIFO
- * and throw them away.
- */
- while (1) {
- dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
- if (!dummy)
- break;
- dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
- }
-}
-
-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);
- 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 == bcm43xx_current_radio(bcm)->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 = bcm43xx_current_radio(bcm)->channel;
- bcm->noisecalc.calculation_running = 1;
- bcm->noisecalc.nr_samples = 0;
-
- bcm43xx_generate_noise_sample(bcm);
-}
-
-static void handle_irq_noise(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- 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;
-
- bcm->stats.noise = average;
-drop_calculation:
- bcm->noisecalc.calculation_running = 0;
- return;
- }
-generate_new:
- bcm43xx_generate_noise_sample(bcm);
-}
-
-static 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 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 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 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);
- }
-}
-
-/* Interrupt handler bottom-half */
-static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
-{
- u32 reason;
- u32 dma_reason[6];
- u32 merged_dma_reason = 0;
- int i, 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->irq_lock, flags);
- reason = bcm->irq_reason;
- for (i = 5; i >= 0; i--) {
- dma_reason[i] = bcm->dma_reason[i];
- merged_dma_reason |= dma_reason[i];
- }
-
- 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.
- */
- printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
- bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
- }
- if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) {
- printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
- "0x%08X, 0x%08X, 0x%08X, "
- "0x%08X, 0x%08X, 0x%08X\n",
- dma_reason[0], dma_reason[1],
- dma_reason[2], dma_reason[3],
- dma_reason[4], dma_reason[5]);
- bcm43xx_controller_restart(bcm, "DMA error");
- mmiowb();
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- return;
- }
- if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) {
- printkl(KERN_ERR PFX "DMA error: "
- "0x%08X, 0x%08X, 0x%08X, "
- "0x%08X, 0x%08X, 0x%08X\n",
- dma_reason[0], dma_reason[1],
- dma_reason[2], dma_reason[3],
- dma_reason[4], dma_reason[5]);
- }
-
- 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. */
- if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
- if (bcm43xx_using_pio(bcm))
- bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
- else
- bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
- /* We intentionally don't set "activity" to 1, here. */
- }
- assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
- assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
- if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
- if (bcm43xx_using_pio(bcm))
- bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
- else
- bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3);
- activity = 1;
- }
- assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE));
- assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE));
- bcmirq_handled(BCM43xx_IRQ_RX);
-
- if (reason & BCM43xx_IRQ_XMIT_STATUS) {
- handle_irq_transmit_status(bcm);
- activity = 1;
- //TODO: In AP mode, this also causes sending of powersave responses.
- bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
- }
-
- /* 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);
- mmiowb();
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
-}
-
-static void pio_irq_workaround(struct bcm43xx_private *bcm,
- u16 base, int queueidx)
-{
- 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 */
- 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);
-
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON,
- bcm->dma_reason[0]);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
- bcm->dma_reason[1]);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
- bcm->dma_reason[2]);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
- bcm->dma_reason[3]);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
- bcm->dma_reason[4]);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON,
- bcm->dma_reason[5]);
-}
-
-/* Interrupt handler top-half */
-static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id)
-{
- irqreturn_t ret = IRQ_HANDLED;
- struct bcm43xx_private *bcm = dev_id;
- u32 reason;
-
- if (!bcm)
- return IRQ_NONE;
-
- spin_lock(&bcm->irq_lock);
-
- reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- if (reason == 0xffffffff) {
- /* irq not for us (shared irq) */
- ret = IRQ_NONE;
- goto out;
- }
- reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
- if (!reason)
- goto out;
-
- assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
- assert(bcm->current_core->id == BCM43xx_COREID_80211);
-
- bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON)
- & 0x0001DC00;
- bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
- & 0x0000DC00;
- bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
- & 0x0000DC00;
- bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
- & 0x0001DC00;
- bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
- & 0x0000DC00;
- bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON)
- & 0x0000DC00;
-
- bcm43xx_interrupt_ack(bcm, reason);
-
- /* 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);
-
-out:
- mmiowb();
- spin_unlock(&bcm->irq_lock);
-
- return ret;
-}
-
-static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-
- if (bcm->firmware_norelease && !force)
- return; /* Suspending or controller reset. */
- release_firmware(phy->ucode);
- phy->ucode = NULL;
- release_firmware(phy->pcm);
- phy->pcm = NULL;
- release_firmware(phy->initvals0);
- phy->initvals0 = NULL;
- release_firmware(phy->initvals1);
- phy->initvals1 = NULL;
-}
-
-static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- u8 rev = bcm->current_core->rev;
- int err = 0;
- int nr;
- char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
-
- if (!phy->ucode) {
- snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
- (rev >= 5 ? 5 : rev),
- modparam_fwpostfix);
- err = request_firmware(&phy->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 (!phy->pcm) {
- snprintf(buf, ARRAY_SIZE(buf),
- "bcm43xx_pcm%d%s.fw",
- (rev < 5 ? 4 : 5),
- modparam_fwpostfix);
- err = request_firmware(&phy->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 (!phy->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(&phy->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 (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {
- printk(KERN_ERR PFX "InitVals fileformat error.\n");
- goto error;
- }
- }
-
- if (!phy->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(&phy->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 (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {
- printk(KERN_ERR PFX "InitVals fileformat error.\n");
- goto error;
- }
- }
- }
-
-out:
- return err;
-error:
- bcm43xx_release_firmware(bcm, 1);
- 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)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- const __be32 *data;
- unsigned int i, len;
-
- /* Upload Microcode. */
- data = (__be32 *)(phy->ucode->data);
- len = phy->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 = (__be32 *)(phy->pcm->data);
- len = phy->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);
- }
-}
-
-static int 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 (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
- 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 int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- int err;
-
- err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,
- phy->initvals0->size / sizeof(struct bcm43xx_initval));
- if (err)
- goto out;
- if (phy->initvals1) {
- err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,
- phy->initvals1->size / sizeof(struct bcm43xx_initval));
- if (err)
- goto out;
- }
-out:
- return err;
-}
-
-static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
-{
- int err;
-
- bcm->irq = bcm->pci_dev->irq;
- err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
- IRQF_SHARED, KBUILD_MODNAME, bcm);
- if (err)
- printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
-
- return err;
-}
-
-/* Switch to the core used to write the GPIO register.
- * This is either the ChipCommon, or the PCI core.
- */
-static 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 (unlikely(err == -ENODEV)) {
- printk(KERN_ERR PFX "gpio error: "
- "Neither ChipCommon nor PCI core available!\n");
- }
- }
-
- return err;
-}
-
-/* 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, set;
-
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
- & 0xFFFF3FFF);
-
- bcm43xx_leds_switch_all(bcm, 0);
- bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
- bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
-
- mask = 0x0000001F;
- set = 0x0000000F;
- if (bcm->chip_id == 0x4301) {
- 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) {
- 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) | set);
- err = bcm43xx_switch_core(bcm, old_core);
-out:
- return err;
-}
-
-/* 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)
-{
- bcm->mac_suspended--;
- assert(bcm->mac_suspended >= 0);
- if (bcm->mac_suspended == 0) {
- 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;
-
- assert(bcm->mac_suspended >= 0);
- if (bcm->mac_suspended == 0) {
- 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 = 10000; i; i--) {
- tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- if (tmp & BCM43xx_IRQ_READY)
- goto out;
- udelay(1);
- }
- printkl(KERN_ERR PFX "MAC suspend failed\n");
- }
-out:
- bcm->mac_suspended++;
-}
-
-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)
- net_dev->type = ARPHRD_IEEE80211;
- else
- net_dev->type = ARPHRD_ETHER;
-
- status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
- /* Reset status to infrastructured mode */
- status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
- 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_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(); /* TODO */
- break;
- case IW_MODE_INFRA:
- /* nothing to be done here... */
- break;
- default:
- 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);
-
- 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() */
-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);
- bcm43xx_release_firmware(bcm, 0);
-}
-
-/* Initialize the chip
- * http://bcm-specs.sipsolutions.net/ChipInit
- */
-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 i, 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);
-
- bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
- i = 0;
- while (1) {
- value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- if (value32 == BCM43xx_IRQ_READY)
- break;
- i++;
- if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
- printk(KERN_ERR PFX "IRQ_READY timeout\n");
- err = -ENODEV;
- goto err_release_fw;
- }
- udelay(10);
- }
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-
- value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_REVISION);
-
- dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x "
- "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", value16,
- bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_PATCHLEVEL),
- (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_DATE) >> 12) & 0xf,
- (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_DATE) >> 8) & 0xf,
- bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_DATE) & 0xff,
- (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_TIME) >> 11) & 0x1f,
- (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_TIME) >> 5) & 0x3f,
- bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_TIME) & 0x1f);
-
- if ( value16 > 0x128 ) {
- printk(KERN_ERR PFX
- "Firmware: no support for microcode extracted "
- "from version 4.x binary drivers.\n");
- err = -EOPNOTSUPP;
- goto err_release_fw;
- }
-
- err = bcm43xx_gpio_init(bcm);
- if (err)
- goto err_release_fw;
-
- err = bcm43xx_upload_initvals(bcm);
- if (err)
- goto err_gpio_cleanup;
- bcm43xx_radio_turn_on(bcm);
- bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
- printk(KERN_INFO PFX "Radio %s by hardware\n",
- (bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
-
- bcm43xx_write16(bcm, 0x03E6, 0x0000);
- err = bcm43xx_phy_init(bcm);
- if (err)
- goto err_radio_off;
-
- /* Select initial Interference Mitigation. */
- 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 (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);
-
- value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
- value32 |= 0x100000;
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
-
- if (bcm43xx_using_pio(bcm)) {
- 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);
-
- /* 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);
- 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_DMA0_IRQ_MASK, 0x0001DC00);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
-
- 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);
-err_gpio_cleanup:
- bcm43xx_gpio_cleanup(bcm);
-err_release_fw:
- bcm43xx_release_firmware(bcm, 1);
- goto out;
-}
-
-/* Validate chip access
- * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
-static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
-{
- 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)
- goto error;
- bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
- 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)
- goto error;
-
- value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- if (value != 0x00000000)
- goto error;
-
- return 0;
-error:
- printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
- return -ENODEV;
-}
-
-static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
-{
- /* Initialize a "phyinfo" structure. The structure is already
- * zeroed out.
- * This is called on insmod time to initialize members.
- */
- phy->savedpctlreg = 0xFFFF;
- spin_lock_init(&phy->lock);
-}
-
-static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
-{
- /* Initialize a "radioinfo" structure. The structure is already
- * zeroed out.
- * This is called on insmod time to initialize members.
- */
- radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
- radio->channel = 0xFF;
- radio->initial_channel = 0xFF;
-}
-
-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_80211, 0, sizeof(struct bcm43xx_coreinfo)
- * BCM43xx_MAX_80211_CORES);
- memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
- * BCM43xx_MAX_80211_CORES);
- bcm->nr_80211_available = 0;
- bcm->current_core = NULL;
- bcm->active_80211_core = NULL;
-
- /* 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 & 0x8FF0) >> 4;
- core_rev = (sb_id_hi & 0x7000) >> 8;
- 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.available = 1;
- 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;
- 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;
- 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);
- dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
- if (bcm->core_chipcommon.available) {
- dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x\n",
- core_id, core_rev, core_vendor);
- 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)
- 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 & 0x8FF0) >> 4;
- core_rev = ((sb_id_hi & 0xF) | ((sb_id_hi & 0x7000) >> 8));
- core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
-
- dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x\n",
- current_core, core_id, core_rev, core_vendor);
-
- core = NULL;
- switch (core_id) {
- case BCM43xx_COREID_PCI:
- case BCM43xx_COREID_PCIE:
- core = &bcm->core_pci;
- if (core->available) {
- printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
- continue;
- }
- break;
- case BCM43xx_COREID_80211:
- for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
- core = &(bcm->core_80211[i]);
- ext_80211 = &(bcm->core_80211_ext[i]);
- if (!core->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 (1 /*bcm->pci_dev->device != 0x4324*/ ) {
- /* TODO: A PHY */
- dprintk(KERN_INFO PFX "Ignoring additional 802.11a core.\n");
- continue;
- }
- }
- switch (core_rev) {
- case 2:
- case 4:
- case 5:
- case 6:
- case 7:
- case 9:
- case 10:
- break;
- default:
- printk(KERN_WARNING PFX
- "Unsupported 80211 core revision %u\n",
- core_rev);
- }
- bcm->nr_80211_available++;
- core->priv = ext_80211;
- 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;
- }
- if (core) {
- core->available = 1;
- core->id = core_id;
- core->rev = core_rev;
- core->index = current_core;
- }
- }
-
- if (!bcm->core_80211[0].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 (bcm43xx_current_phy(bcm)->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->initialized = 0;
-}
-
-/* http://bcm-specs.sipsolutions.net/80211Init */
-static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
- int active_wlcore)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u32 ucodeflags;
- int err;
- u32 sbimconfiglow;
- u8 limit;
-
- if (bcm->core_pci.rev <= 5 && bcm->core_pci.id != BCM43xx_COREID_PCIE) {
- 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
- sbimconfiglow |= 0x53;
- 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 (phy->type == BCM43xx_PHYTYPE_G) {
- ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
- if (phy->rev == 1)
- ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
- if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
- ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
- } else if (phy->type == BCM43xx_PHYTYPE_B) {
- ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
- if (phy->rev >= 2 && 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 (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 (active_wlcore) {
- if (bcm43xx_using_pio(bcm)) {
- err = bcm43xx_pio_init(bcm);
- } else {
- err = bcm43xx_dma_init(bcm);
- if (err == -ENOSYS)
- 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);
-
- if (active_wlcore) {
- if (radio->initial_channel != 0xFF)
- bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0);
- }
-
- /* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
- * We enable it later.
- */
- bcm->current_core->initialized = 1;
-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;
- err = bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
- if (err)
- goto out;
- err = 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 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 = 0;
-
- bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-
- if (bcm->core_chipcommon.available) {
- err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
- if (err)
- goto out;
-
- bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
-
- /* this function is always called when a PCI core is mapped */
- err = bcm43xx_switch_core(bcm, &bcm->core_pci);
- if (err)
- goto out;
- } else
- bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
-
- bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
-
-out:
- return err;
-}
-
-static u32 bcm43xx_pcie_reg_read(struct bcm43xx_private *bcm, u32 address)
-{
- bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address);
- return bcm43xx_read32(bcm, BCM43xx_PCIECORE_REG_DATA);
-}
-
-static void bcm43xx_pcie_reg_write(struct bcm43xx_private *bcm, u32 address,
- u32 data)
-{
- bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address);
- bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_DATA, data);
-}
-
-static void bcm43xx_pcie_mdio_write(struct bcm43xx_private *bcm, u8 dev, u8 reg,
- u16 data)
-{
- int i;
-
- bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0x0082);
- bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_DATA, BCM43xx_PCIE_MDIO_ST |
- BCM43xx_PCIE_MDIO_WT | (dev << BCM43xx_PCIE_MDIO_DEV) |
- (reg << BCM43xx_PCIE_MDIO_REG) | BCM43xx_PCIE_MDIO_TA |
- data);
- udelay(10);
-
- for (i = 0; i < 10; i++) {
- if (bcm43xx_read32(bcm, BCM43xx_PCIECORE_MDIO_CTL) &
- BCM43xx_PCIE_MDIO_TC)
- break;
- msleep(1);
- }
- bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0);
-}
-
-/* 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->current_core->rev < 6 &&
- bcm->current_core->id == BCM43xx_COREID_PCI) {
- 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;
- }
- }
-
- if (bcm->current_core->id == BCM43xx_COREID_PCI) {
- value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
- value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
- bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
-
- if (bcm->current_core->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);
- } else if (bcm->current_core->rev >= 11) {
- value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
- value |= BCM43xx_SBTOPCI2_MEMREAD_MULTI;
- bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
- }
- } else {
- if (bcm->current_core->rev == 0 || bcm->current_core->rev == 1) {
- value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_TLP_WORKAROUND);
- value |= 0x8;
- bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_TLP_WORKAROUND,
- value);
- }
- if (bcm->current_core->rev == 0) {
- bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
- BCM43xx_SERDES_RXTIMER, 0x8128);
- bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
- BCM43xx_SERDES_CDR, 0x0100);
- bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
- BCM43xx_SERDES_CDR_BW, 0x1466);
- } else if (bcm->current_core->rev == 1) {
- value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_DLLP_LINKCTL);
- value |= 0x40;
- bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_DLLP_LINKCTL,
- value);
- }
- }
-out_switch_back:
- err = bcm43xx_switch_core(bcm, old_core);
-out:
- return err;
-}
-
-static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-
- if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
- return;
-
- bcm43xx_mac_suspend(bcm);
- bcm43xx_phy_lo_g_measure(bcm);
- bcm43xx_mac_enable(bcm);
-}
-
-static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
-{
- 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);
- }
-}
-
-static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
-{
- /* Update device statistics. */
- bcm43xx_calculate_link_quality(bcm);
-}
-
-static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
-{
- bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
- //TODO for APHY (temperature?)
-}
-
-static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- int radio_hw_enable;
-
- /* check if radio hardware enabled status changed */
- radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
- if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
- bcm->radio_hw_enable = radio_hw_enable;
- printk(KERN_INFO PFX "Radio hardware status changed to %s\n",
- (radio_hw_enable == 0) ? "disabled" : "enabled");
- bcm43xx_leds_update(bcm, 0);
- }
- 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
- }
- }
-}
-
-static void do_periodic_work(struct bcm43xx_private *bcm)
-{
- if (bcm->periodic_state % 120 == 0)
- bcm43xx_periodic_every120sec(bcm);
- if (bcm->periodic_state % 60 == 0)
- bcm43xx_periodic_every60sec(bcm);
- if (bcm->periodic_state % 30 == 0)
- bcm43xx_periodic_every30sec(bcm);
- if (bcm->periodic_state % 15 == 0)
- bcm43xx_periodic_every15sec(bcm);
- bcm43xx_periodic_every1sec(bcm);
-
- schedule_delayed_work(&bcm->periodic_work, HZ);
-}
-
-static void bcm43xx_periodic_work_handler(struct work_struct *work)
-{
- struct bcm43xx_private *bcm =
- container_of(work, struct bcm43xx_private, periodic_work.work);
- struct net_device *net_dev = bcm->net_dev;
- unsigned long flags;
- u32 savedirqs = 0;
- unsigned long orig_trans_start = 0;
-
- mutex_lock(&bcm->mutex);
- /* keep from doing and rearming periodic work if shutting down */
- if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT)
- goto unlock_mutex;
- if (unlikely(bcm->periodic_state % 60 == 0)) {
- /* Periodic work will take a long time, so we want it to
- * be preemtible.
- */
-
- netif_tx_lock_bh(net_dev);
- /* We must fake a started transmission here, as we are going to
- * disable TX. If we wouldn't fake a TX, it would be possible to
- * trigger the netdev watchdog, if the last real TX is already
- * some time on the past (slightly less than 5secs)
- */
- orig_trans_start = net_dev->trans_start;
- net_dev->trans_start = jiffies;
- netif_stop_queue(net_dev);
- netif_tx_unlock_bh(net_dev);
-
- spin_lock_irqsave(&bcm->irq_lock, flags);
- bcm43xx_mac_suspend(bcm);
- if (bcm43xx_using_pio(bcm))
- bcm43xx_pio_freeze_txqueues(bcm);
- savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- bcm43xx_synchronize_irq(bcm);
- } else {
- /* Periodic work should take short time, so we want low
- * locking overhead.
- */
- spin_lock_irqsave(&bcm->irq_lock, flags);
- }
-
- do_periodic_work(bcm);
-
- if (unlikely(bcm->periodic_state % 60 == 0)) {
- spin_lock_irqsave(&bcm->irq_lock, flags);
- tasklet_enable(&bcm->isr_tasklet);
- bcm43xx_interrupt_enable(bcm, savedirqs);
- if (bcm43xx_using_pio(bcm))
- bcm43xx_pio_thaw_txqueues(bcm);
- bcm43xx_mac_enable(bcm);
- netif_wake_queue(bcm->net_dev);
- net_dev->trans_start = orig_trans_start;
- }
- mmiowb();
- bcm->periodic_state++;
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
-unlock_mutex:
- mutex_unlock(&bcm->mutex);
-}
-
-void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
-{
- struct delayed_work *work = &bcm->periodic_work;
-
- assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
- INIT_DELAYED_WORK(work, bcm43xx_periodic_work_handler);
- schedule_delayed_work(work, 0);
-}
-
-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);
-}
-
-static int bcm43xx_rng_read(struct hwrng *rng, u32 *data)
-{
- struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv;
- unsigned long flags;
-
- spin_lock_irqsave(&(bcm)->irq_lock, flags);
- *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG);
- spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
-
- return (sizeof(u16));
-}
-
-static void bcm43xx_rng_exit(struct bcm43xx_private *bcm)
-{
- hwrng_unregister(&bcm->rng);
-}
-
-static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
-{
- int err;
-
- snprintf(bcm->rng_name, ARRAY_SIZE(bcm->rng_name),
- "%s_%s", KBUILD_MODNAME, bcm->net_dev->name);
- bcm->rng.name = bcm->rng_name;
- bcm->rng.data_read = bcm43xx_rng_read;
- bcm->rng.priv = (unsigned long)bcm;
- err = hwrng_register(&bcm->rng);
- if (err)
- printk(KERN_ERR PFX "RNG init failed (%d)\n", err);
-
- return err;
-}
-
-void bcm43xx_cancel_work(struct bcm43xx_private *bcm)
-{
- /* The system must be unlocked when this routine is entered.
- * If not, the next 2 steps may deadlock */
- cancel_work_sync(&bcm->restart_work);
- cancel_delayed_work_sync(&bcm->periodic_work);
-}
-
-static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
-{
- int ret = 0;
- int i, err;
- struct bcm43xx_coreinfo *core;
-
- bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
- for (i = 0; i < bcm->nr_80211_available; i++) {
- core = &(bcm->core_80211[i]);
- assert(core->available);
- if (!core->initialized)
- continue;
- err = bcm43xx_switch_core(bcm, core);
- if (err) {
- dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
- "switch_core failed (%d)\n", err);
- ret = err;
- continue;
- }
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
- bcm43xx_wireless_core_cleanup(bcm);
- if (core == bcm->active_80211_core)
- bcm->active_80211_core = NULL;
- }
- free_irq(bcm->irq, bcm);
- bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
-
- return ret;
-}
-
-/* This is the opposite of bcm43xx_init_board() */
-static void bcm43xx_free_board(struct bcm43xx_private *bcm)
-{
- bcm43xx_rng_exit(bcm);
- bcm43xx_sysfs_unregister(bcm);
-
- mutex_lock(&(bcm)->mutex);
- bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
- mutex_unlock(&(bcm)->mutex);
-
- bcm43xx_cancel_work(bcm);
-
- mutex_lock(&(bcm)->mutex);
- bcm43xx_shutdown_all_wireless_cores(bcm);
- bcm43xx_pctl_set_crystal(bcm, 0);
- mutex_unlock(&(bcm)->mutex);
-}
-
-static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy)
-{
- phy->antenna_diversity = 0xFFFF;
- memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
- memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
-
- /* Flags */
- phy->calibrated = 0;
- phy->is_locked = 0;
-
- if (phy->_lo_pairs) {
- memset(phy->_lo_pairs, 0,
- sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT);
- }
- memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
-}
-
-static void prepare_radiodata_for_init(struct bcm43xx_private *bcm,
- struct bcm43xx_radioinfo *radio)
-{
- int i;
-
- /* Set default attenuation values. */
- 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;
- radio->txpwr_offset = 0;
-
- /* NRSSI */
- radio->nrssislope = 0;
- for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++)
- radio->nrssi[i] = -1000;
- for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++)
- radio->nrssi_lt[i] = i;
-
- radio->lofcal = 0xFFFF;
- radio->initval = 0xFFFF;
-
- radio->aci_enable = 0;
- radio->aci_wlan_automatic = 0;
- radio->aci_hw_rssi = 0;
-}
-
-static void prepare_priv_for_init(struct bcm43xx_private *bcm)
-{
- int i;
- struct bcm43xx_coreinfo *core;
- struct bcm43xx_coreinfo_80211 *wlext;
-
- assert(!bcm->active_80211_core);
-
- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
-
- /* Flags */
- bcm->was_initialized = 0;
- bcm->reg124_set_0x4 = 0;
-
- /* Stats */
- memset(&bcm->stats, 0, sizeof(bcm->stats));
-
- /* Wireless core data */
- for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
- core = &(bcm->core_80211[i]);
- wlext = core->priv;
-
- if (!core->available)
- continue;
- assert(wlext == &(bcm->core_80211_ext[i]));
-
- prepare_phydata_for_init(&wlext->phy);
- prepare_radiodata_for_init(bcm, &wlext->radio);
- }
-
- /* IRQ related flags */
- bcm->irq_reason = 0;
- memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason));
- bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
-
- bcm->mac_suspended = 1;
-
- /* Noise calculation context */
- memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
-
- /* Periodic work context */
- bcm->periodic_state = 0;
-}
-
-static int wireless_core_up(struct bcm43xx_private *bcm,
- int active_wlcore)
-{
- int err;
-
- if (!bcm43xx_core_enabled(bcm))
- bcm43xx_wireless_core_reset(bcm, 1);
- if (!active_wlcore)
- bcm43xx_wireless_core_mark_inactive(bcm);
- err = bcm43xx_wireless_core_init(bcm, active_wlcore);
- if (err)
- goto out;
- if (!active_wlcore)
- bcm43xx_radio_turn_off(bcm);
-out:
- return err;
-}
-
-/* Select and enable the "to be used" wireless core.
- * Locking: bcm->mutex must be aquired before calling this.
- * bcm->irq_lock must not be aquired.
- */
-int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
- int phytype)
-{
- int i, err;
- struct bcm43xx_coreinfo *active_core = NULL;
- struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
- struct bcm43xx_coreinfo *core;
- struct bcm43xx_coreinfo_80211 *wlext;
- int adjust_active_sbtmstatelow = 0;
-
- might_sleep();
-
- if (phytype < 0) {
- /* If no phytype is requested, select the first core. */
- assert(bcm->core_80211[0].available);
- wlext = bcm->core_80211[0].priv;
- phytype = wlext->phy.type;
- }
- /* Find the requested core. */
- for (i = 0; i < bcm->nr_80211_available; i++) {
- core = &(bcm->core_80211[i]);
- wlext = core->priv;
- if (wlext->phy.type == phytype) {
- active_core = core;
- active_wlext = wlext;
- break;
- }
- }
- if (!active_core)
- return -ESRCH; /* No such PHYTYPE on this board. */
-
- if (bcm->active_80211_core) {
- /* We already selected a wl core in the past.
- * So first clean up everything.
- */
- dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n");
- ieee80211softmac_stop(bcm->net_dev);
- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
- err = bcm43xx_disable_interrupts_sync(bcm);
- assert(!err);
- tasklet_enable(&bcm->isr_tasklet);
- err = bcm43xx_shutdown_all_wireless_cores(bcm);
- if (err)
- goto error;
- /* Ok, everything down, continue to re-initialize. */
- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
- }
-
- /* Reset all data structures. */
- prepare_priv_for_init(bcm);
-
- err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
- if (err)
- goto error;
-
- /* Mark all unused cores "inactive". */
- for (i = 0; i < bcm->nr_80211_available; i++) {
- core = &(bcm->core_80211[i]);
- wlext = core->priv;
-
- if (core == active_core)
- continue;
- err = bcm43xx_switch_core(bcm, core);
- if (err) {
- dprintk(KERN_ERR PFX "Could not switch to inactive "
- "802.11 core (%d)\n", err);
- goto error;
- }
- err = wireless_core_up(bcm, 0);
- if (err) {
- dprintk(KERN_ERR PFX "core_up for inactive 802.11 core "
- "failed (%d)\n", err);
- goto error;
- }
- adjust_active_sbtmstatelow = 1;
- }
-
- /* Now initialize the active 802.11 core. */
- err = bcm43xx_switch_core(bcm, active_core);
- if (err) {
- dprintk(KERN_ERR PFX "Could not switch to active "
- "802.11 core (%d)\n", err);
- goto error;
- }
- if (adjust_active_sbtmstatelow &&
- active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
- u32 sbtmstatelow;
-
- sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
- bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
- }
- err = wireless_core_up(bcm, 1);
- if (err) {
- dprintk(KERN_ERR PFX "core_up for active 802.11 core "
- "failed (%d)\n", err);
- goto error;
- }
- err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
- if (err)
- goto error;
- bcm->active_80211_core = active_core;
-
- bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
- bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
- bcm43xx_security_init(bcm);
- drain_txstatus_queue(bcm);
- ieee80211softmac_start(bcm->net_dev);
-
- /* Let's go! Be careful after enabling the IRQs.
- * Don't switch cores, for example.
- */
- bcm43xx_mac_enable(bcm);
- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
- err = bcm43xx_initialize_irq(bcm);
- if (err)
- goto error;
- bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
-
- dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
- active_wlext->phy.type);
-
- return 0;
-
-error:
- bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
- bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
- return err;
-}
-
-static int bcm43xx_init_board(struct bcm43xx_private *bcm)
-{
- int err;
-
- mutex_lock(&(bcm)->mutex);
-
- tasklet_enable(&bcm->isr_tasklet);
- err = bcm43xx_pctl_set_crystal(bcm, 1);
- if (err)
- goto err_tasklet;
- err = bcm43xx_pctl_init(bcm);
- if (err)
- goto err_crystal_off;
- err = bcm43xx_select_wireless_core(bcm, -1);
- if (err)
- goto err_crystal_off;
- err = bcm43xx_sysfs_register(bcm);
- if (err)
- goto err_wlshutdown;
- err = bcm43xx_rng_init(bcm);
- if (err)
- goto err_sysfs_unreg;
- bcm43xx_periodic_tasks_setup(bcm);
-
- /*FIXME: This should be handled by softmac instead. */
- schedule_delayed_work(&bcm->softmac->associnfo.work, 0);
-
-out:
- mutex_unlock(&(bcm)->mutex);
-
- return err;
-
-err_sysfs_unreg:
- bcm43xx_sysfs_unregister(bcm);
-err_wlshutdown:
- bcm43xx_shutdown_all_wireless_cores(bcm);
-err_crystal_off:
- bcm43xx_pctl_set_crystal(bcm, 0);
-err_tasklet:
- tasklet_disable(&bcm->isr_tasklet);
- 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. */
- pci_iounmap(pci_dev, 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->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 = bcm43xx_current_phy(bcm);
- u16 value;
- u8 phy_analog;
- u8 phy_type;
- u8 phy_rev;
- int phy_rev_ok = 1;
- void *p;
-
- value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
-
- phy_analog = (value & 0xF000) >> 12;
- phy_type = (value & 0x0F00) >> 8;
- phy_rev = (value & 0x000F);
-
- dprintk(KERN_INFO PFX "Detected PHY: Analog: %x, Type %x, Revision %x\n",
- phy_analog, 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 > 8)
- 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;
- };
- bcm->ieee->perfect_rssi = RX_RSSI_MAX;
- bcm->ieee->worst_rssi = 0;
- if (!phy_rev_ok) {
- printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
- phy_rev);
- }
-
- phy->analog = phy_analog;
- 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;
- 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;
- u32 coremask;
-
- err = pci_enable_device(pci_dev);
- if (err) {
- printk(KERN_ERR PFX "pci_enable_device() failed\n");
- goto out;
- }
- err = pci_request_regions(pci_dev, KBUILD_MODNAME);
- if (err) {
- printk(KERN_ERR PFX "pci_request_regions() failed\n");
- goto err_pci_disable;
- }
- /* enable PCI bus-mastering */
- pci_set_master(pci_dev);
- bcm->mmio_addr = pci_iomap(pci_dev, 0, ~0UL);
- if (!bcm->mmio_addr) {
- printk(KERN_ERR PFX "pci_iomap() failed\n");
- err = -EIO;
- goto err_pci_release;
- }
- net_dev->base_addr = (unsigned long)bcm->mmio_addr;
-
- err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
- &bcm->board_vendor);
- if (err)
- goto err_iounmap;
- err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
- &bcm->board_type);
- if (err)
- goto err_iounmap;
-
- bcm->board_revision = bcm->pci_dev->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;
-
- /* Attach all IO cores to the backplane. */
- coremask = 0;
- 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);
- if (err) {
- printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
- goto err_chipset_detach;
- }
-
- err = bcm43xx_sprom_extract(bcm);
- if (err)
- goto err_chipset_detach;
- err = bcm43xx_leds_init(bcm);
- if (err)
- goto err_chipset_detach;
-
- for (i = 0; i < bcm->nr_80211_available; 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);
- }
- err = bcm43xx_geo_init(bcm);
- if (err)
- goto err_80211_unwind;
- bcm43xx_pctl_set_crystal(bcm, 0);
-
- /* Set the MAC address in the networking subsystem */
- if (is_valid_ether_addr(bcm->sprom.et1macaddr))
- memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
- else
- memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
-
- 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->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);
-err_iounmap:
- pci_iounmap(pci_dev, bcm->mmio_addr);
-err_pci_release:
- pci_release_regions(pci_dev);
-err_pci_disable:
- pci_disable_device(pci_dev);
- printk(KERN_ERR PFX "Unable to attach board\n");
- goto out;
-}
-
-/* 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 (bcm43xx_using_pio(bcm))
- err = bcm43xx_pio_tx(bcm, txb);
- else
- err = bcm43xx_dma_tx(bcm, txb);
- bcm->net_dev->trans_start = jiffies;
-
- return err;
-}
-
-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;
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (bcm43xx_status(bcm) == BCM43xx_STAT_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;
- }
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-}
-
-/* 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");
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
-
- for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
- if (sec->flags & (1<<keyidx)) {
- secinfo->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(", .active_key = %d", sec->active_key);
- }
- if (sec->flags & SEC_UNICAST_GROUP) {
- secinfo->unicast_uses_group = sec->unicast_uses_group;
- dprintk(", .unicast_uses_group = %d", sec->unicast_uses_group);
- }
- if (sec->flags & SEC_LEVEL) {
- secinfo->level = sec->level;
- dprintk(", .level = %d", sec->level);
- }
- if (sec->flags & SEC_ENABLED) {
- secinfo->enabled = sec->enabled;
- dprintk(", .enabled = %d", sec->enabled);
- }
- if (sec->flags & SEC_ENCRYPT) {
- secinfo->encrypt = sec->encrypt;
- dprintk(", .encrypt = %d", sec->encrypt);
- }
- if (sec->flags & SEC_AUTH_MODE) {
- secinfo->auth_mode = sec->auth_mode;
- dprintk(", .auth_mode = %d", sec->auth_mode);
- }
- dprintk("\n");
- if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
- !bcm->ieee->host_encrypt) {
- if (secinfo->enabled) {
- /* upload WEP keys to hardware */
- char null_address[6] = { 0 };
- u8 algorithm = 0;
- for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
- if (!(sec->flags & (1<<keyidx)))
- continue;
- switch (sec->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->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-}
-
-/* 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->irq_lock, flags);
- if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
- err = bcm43xx_tx(bcm, txb);
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
-
- if (unlikely(err))
- return NETDEV_TX_BUSY;
- return NETDEV_TX_OK;
-}
-
-static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
-{
- struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
-
- spin_lock_irqsave(&bcm->irq_lock, flags);
- bcm43xx_controller_restart(bcm, "TX timeout");
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
-}
-
-#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);
- if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
- bcm43xx_interrupt_handler(bcm->irq, bcm);
- 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);
- int err;
-
- ieee80211softmac_stop(net_dev);
- err = bcm43xx_disable_interrupts_sync(bcm);
- assert(!err);
- bcm43xx_free_board(bcm);
- bcm43xx_cancel_work(bcm);
-
- return 0;
-}
-
-static int bcm43xx_init_private(struct bcm43xx_private *bcm,
- struct net_device *net_dev,
- struct pci_dev *pci_dev)
-{
- bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
- bcm->ieee = netdev_priv(net_dev);
- bcm->softmac = ieee80211_priv(net_dev);
- bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
-
- bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
- bcm->mac_suspended = 1;
- bcm->pci_dev = pci_dev;
- bcm->net_dev = net_dev;
- bcm->bad_frames_preempt = modparam_bad_frames_preempt;
- spin_lock_init(&bcm->irq_lock);
- spin_lock_init(&bcm->leds_lock);
- mutex_init(&bcm->mutex);
- tasklet_init(&bcm->isr_tasklet,
- (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
- (unsigned long)bcm);
- tasklet_disable_nosync(&bcm->isr_tasklet);
- if (modparam_pio)
- bcm->__using_pio = 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;
-
- return 0;
-}
-
-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;
- int err;
-
-#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_NETDEV_DEV(net_dev, &pdev->dev);
-
- net_dev->open = bcm43xx_net_open;
- net_dev->stop = bcm43xx_net_stop;
- 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;
- SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
-
- /* initialize the bcm43xx_private struct */
- bcm = bcm43xx_priv(net_dev);
- memset(bcm, 0, sizeof(*bcm));
- err = bcm43xx_init_private(bcm, net_dev, pdev);
- if (err)
- goto err_free_netdev;
-
- pci_set_drvdata(pdev, net_dev);
-
- err = bcm43xx_attach_board(bcm);
- if (err)
- goto err_free_netdev;
-
- 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_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);
- free_ieee80211softmac(net_dev);
-}
-
-/* Hard-reset the chip. Do not call this directly.
- * Use bcm43xx_controller_restart()
- */
-static void bcm43xx_chip_reset(struct work_struct *work)
-{
- struct bcm43xx_private *bcm =
- container_of(work, struct bcm43xx_private, restart_work);
- struct bcm43xx_phyinfo *phy;
- int err = -ENODEV;
-
- bcm43xx_cancel_work(bcm);
- mutex_lock(&(bcm)->mutex);
- if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
- phy = bcm43xx_current_phy(bcm);
- err = bcm43xx_select_wireless_core(bcm, phy->type);
- if (!err)
- bcm43xx_periodic_tasks_setup(bcm);
- }
- mutex_unlock(&(bcm)->mutex);
-
- printk(KERN_ERR PFX "Controller restart%s\n",
- (err == 0) ? "ed" : " failed");
-}
-
-/* Hard-reset the chip.
- * This can be called from interrupt or process context.
- * bcm->irq_lock must be locked.
- */
-void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
-{
- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
- return;
- printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
- INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset);
- schedule_work(&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);
- int err;
-
- dprintk(KERN_INFO PFX "Suspending...\n");
-
- netif_device_detach(net_dev);
- bcm->was_initialized = 0;
- if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
- bcm->was_initialized = 1;
- ieee80211softmac_stop(net_dev);
- err = bcm43xx_disable_interrupts_sync(bcm);
- 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);
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Failure with pci_enable_device!\n");
- return err;
- }
- pci_restore_state(pdev);
-
- bcm43xx_chipset_attach(bcm);
- if (bcm->was_initialized)
- err = bcm43xx_init_board(bcm);
- if (err) {
- printk(KERN_ERR PFX "Resume failed!\n");
- return err;
- }
- netif_device_attach(net_dev);
-
- dprintk(KERN_INFO PFX "Device resumed.\n");
-
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-static struct pci_driver bcm43xx_pci_driver = {
- .name = KBUILD_MODNAME,
- .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 KBUILD_MODNAME " driver\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)
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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"
-
-#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))
-
-
-/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
-static inline
-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 (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 (bcm43xx_current_phy(bcm)->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_a(u8 channel)
-{
- return (5000 + (5 * channel));
-}
-static inline
-int bcm43xx_channel_to_freq_bg(u8 channel)
-{
- int freq;
-
- 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 (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
- return bcm43xx_channel_to_freq_a(channel);
- return bcm43xx_channel_to_freq_bg(channel);
-}
-
-void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
-void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
-
-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);
-
-int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
- int phytype);
-
-void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
-
-void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
-void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
-
-void bcm43xx_cancel_work(struct bcm43xx_private *bcm);
-void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
-
-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_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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 <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-
-#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);
-
-
-static inline
-void bcm43xx_voluntary_preempt(void)
-{
- assert(!in_atomic() && !in_irq() &&
- !in_interrupt() && !irqs_disabled());
-#ifndef CONFIG_PREEMPT
- cond_resched();
-#endif /* CONFIG_PREEMPT */
-}
-
-void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-
- 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 = bcm43xx_current_phy(bcm);
-
- 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);
- mmiowb();
- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val);
-}
-
-void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
- if (phy->calibrated)
- return;
- if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
- bcm43xx_wireless_core_reset(bcm, 0);
- bcm43xx_phy_initg(bcm);
- bcm43xx_wireless_core_reset(bcm, 1);
- }
- phy->calibrated = 1;
-}
-
-/* Connect the PHY
- * http://bcm-specs.sipsolutions.net/SetPHY
- */
-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)
- goto out;
-
- flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
- if (connect) {
- if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL))
- return -ENODEV;
- flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
- bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
- } else {
- if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL))
- return -ENODEV;
- flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
- bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
- }
-out:
- phy->connected = connect;
- if (connect)
- dprintk(KERN_INFO PFX "PHY connected\n");
- else
- 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 = 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;
-
- assert(phy->type != BCM43xx_PHYTYPE_A);
- if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
- (bcm->board_type == 0x0416))
- return;
-
- bcm43xx_phy_write(bcm, 0x0028, 0x8018);
- bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF);
-
- 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->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);
- 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 = bcm43xx_current_phy(bcm);
- u16 offset = 0x0000;
-
- if (phy->rev == 1)
- offset = 0x4C00;
-
- 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_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);
- }
-
- 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_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);
-
- if (phy->rev >= 6) {
- bcm43xx_phy_write(bcm, 0x0426, (bcm43xx_phy_read(bcm, 0x0426)
- & 0xFFFC));
- bcm43xx_phy_write(bcm, 0x0426, (bcm43xx_phy_read(bcm, 0x0426)
- & 0xEFFF));
- }
-}
-
-static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- 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_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]);
- for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++)
- bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]);
- for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
- bcm43xx_ilt_write32(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_write(bcm, 0x4000 + i, i);
- for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; 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_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_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
- else
- for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; 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_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
- else if ((phy->rev > 2) && (phy->rev <= 8))
- for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; 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_write32(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
- for (i = 0; i < 4; i++) {
- 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);
-
- if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
- (bcm->board_type == 0x0416) &&
- (bcm->board_revision == 0x0017))
- return;
-
- bcm43xx_ilt_write(bcm, 0x5001, 0x0002);
- bcm43xx_ilt_write(bcm, 0x5002, 0x0001);
- } else {
- for (i = 0; i <= 0x2F; i++)
- 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_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_write(bcm, 0x0401, 0x0002);
- bcm43xx_ilt_write(bcm, 0x0402, 0x0001);
- }
-}
-
-/* Initialize the noisescaletable for APHY */
-static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- 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)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- u16 i;
-
- assert(phy->type == BCM43xx_PHYTYPE_A);
- switch (phy->rev) {
- case 2:
- bcm43xx_phy_write(bcm, 0x008E, 0x3800);
- bcm43xx_phy_write(bcm, 0x0035, 0x03FF);
- bcm43xx_phy_write(bcm, 0x0036, 0x0400);
-
- 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_write(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_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);
-
- for (i = 0; i < 16; i++)
- bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F);
-
- 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_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]);
- for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++)
- bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]);
- for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
- bcm43xx_ilt_write32(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
- bcm43xx_phy_init_noisescaletbl(bcm);
- for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
- bcm43xx_ilt_write32(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
- break;
- case 3:
- for (i = 0; i < 64; i++)
- bcm43xx_ilt_write(bcm, 0x4000 + i, i);
-
- bcm43xx_ilt_write(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_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008);
- for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; 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_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
-
- bcm43xx_phy_write(bcm, 0x0003, 0x1808);
-
- 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);
- }
-}
-
-/* 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 = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- 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 (radio->lofcal == 0xFFFF) {
- TODO();//TODO: LOF Cal
- bcm43xx_radio_set_tx_iq(bcm);
- } else
- bcm43xx_radio_write16(bcm, 0x001E, 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_read(bcm, 0x3001);
- if (phy->rev == 1) {
- bcm43xx_ilt_write(bcm, 0x3001,
- (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87)
- | 0x0058);
- } else {
- 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_write(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 = bcm43xx_current_radio(bcm);
- 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 = bcm43xx_current_radio(bcm);
- 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 = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u16 offset;
- u16 value;
- u8 old_channel;
-
- if (phy->analog == 1)
- bcm43xx_radio_write16(bcm, 0x007A,
- bcm43xx_radio_read16(bcm, 0x007A)
- | 0x0050);
- if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) &&
- (bcm->board_type != 0x0416)) {
- value = 0x2120;
- for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
- bcm43xx_phy_write(bcm, offset, value);
- value += 0x0202;
- }
- }
- 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->analog == 1) {
- 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->analog == 1)
- bcm43xx_phy_write(bcm, 0x0020, 0x3E1C);
- else
- bcm43xx_phy_write(bcm, 0x0020, 0x301C);
-
- if (phy->analog == 0)
- bcm43xx_write16(bcm, 0x03E4, 0x3000);
-
- old_channel = radio->channel;
- /* 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, old_channel, 0);
-
- bcm43xx_phy_write(bcm, 0x0014, 0x0080);
- bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
- bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
-
- 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 = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u16 offset, val;
- u8 old_channel;
-
- bcm43xx_phy_write(bcm, 0x003E, 0x817A);
- bcm43xx_radio_write16(bcm, 0x007A,
- (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058));
- if (radio->revision == 4 ||
- radio->revision == 5) {
- bcm43xx_radio_write16(bcm, 0x0051, 0x0037);
- bcm43xx_radio_write16(bcm, 0x0052, 0x0070);
- bcm43xx_radio_write16(bcm, 0x0053, 0x00B3);
- bcm43xx_radio_write16(bcm, 0x0054, 0x009B);
- 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);
- bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODEFLAGS_OFFSET,
- (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODEFLAGS_OFFSET)
- | 0x00000200));
- }
- if (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);
- bcm43xx_phy_write(bcm, 0x5B, 0x0000);
- bcm43xx_phy_write(bcm, 0x5C, 0x0000);
- }
-
- old_channel = radio->channel;
- if (old_channel >= 8)
- bcm43xx_radio_selectchannel(bcm, 1, 0);
- else
- bcm43xx_radio_selectchannel(bcm, 13, 0);
-
- bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
- bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
- udelay(40);
- if (radio->revision < 6 || radio-> revision == 8) {
- bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C)
- | 0x0002));
- bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
- }
- if (radio->revision <= 2) {
- bcm43xx_radio_write16(bcm, 0x007C, 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, old_channel, 0);
-
- bcm43xx_phy_write(bcm, 0x0014, 0x0200);
- if (radio->revision >= 6)
- bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
- else
- bcm43xx_phy_write(bcm, 0x002A, 0x8AC0);
- bcm43xx_phy_write(bcm, 0x0038, 0x0668);
- bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
- if (radio->revision <= 5)
- bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D)
- & 0xFF80) | 0x0003);
- if (radio->revision <= 2)
- bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
-
- if (phy->analog == 4){
- bcm43xx_write16(bcm, 0x03E4, 0x0009);
- bcm43xx_phy_write(bcm, 0x61, bcm43xx_phy_read(bcm, 0x61) & 0xFFF);
- } else {
- bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004);
- }
- if (phy->type == BCM43xx_PHYTYPE_G)
- bcm43xx_write16(bcm, 0x03E6, 0x0);
- if (phy->type == BCM43xx_PHYTYPE_B) {
- bcm43xx_write16(bcm, 0x03E6, 0x8140);
- bcm43xx_phy_write(bcm, 0x0016, 0x0410);
- bcm43xx_phy_write(bcm, 0x0017, 0x0820);
- bcm43xx_phy_write(bcm, 0x0062, 0x0007);
- bcm43xx_radio_init2050(bcm);
- bcm43xx_phy_lo_g_measure(bcm);
- 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_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] = {0};
- 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);
- if (phy->rev != 1) {
- 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);
- if (phy->rev != 1) {
- 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->analog == 0) {
- bcm43xx_phy_write(bcm, 0x0003, 0x0122);
- } else {
- bcm43xx_phy_write(bcm, 0x000A,
- bcm43xx_phy_read(bcm, 0x000A)
- | 0x2000);
- }
- if (phy->rev != 1) {
- 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;
- }
- }
-
- if (phy->rev != 1) {
- 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
- 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);
- bcm43xx_phy_write(bcm, 0x0015, 0x00C0);
- }
- if (phy->rev > 5) {
- bcm43xx_phy_write(bcm, 0x0811, 0x0400);
- bcm43xx_phy_write(bcm, 0x0015, 0x00C0);
- }
- if (phy->rev >= 2 && phy->connected) {
- tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF;
- if (tmp ==3 || tmp == 5) {
- bcm43xx_phy_write(bcm, 0x04C2, 0x1816);
- bcm43xx_phy_write(bcm, 0x04C3, 0x8006);
- if (tmp == 5) {
- bcm43xx_phy_write(bcm, 0x04CC,
- (bcm43xx_phy_read(bcm, 0x04CC)
- & 0x00FF) | 0x1F00);
- }
- }
- bcm43xx_phy_write(bcm, 0x047E, 0x0078);
- }
- if (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 (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 {
- if (radio->version == 0x2050 && radio->revision == 8) {
- bcm43xx_radio_write16(bcm, 0x0052,
- (radio->txctl1 << 4) | radio->txctl2);
- } 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)
- & 0x0FFF) | (radio->txctl2 << 12));
- }
- if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
- bcm43xx_phy_write(bcm, 0x002E, 0x8075);
- else
- bcm43xx_phy_write(bcm, 0x002E, 0x807F);
- if (phy->rev < 2)
- bcm43xx_phy_write(bcm, 0x002F, 0x0101);
- else
- bcm43xx_phy_write(bcm, 0x002F, 0x0202);
- }
- if (phy->connected || phy->rev >= 2) {
- 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
- * 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 || phy->rev >= 2) {
- if (radio->nrssi[0] == -1000) {
- assert(radio->nrssi[1] == -1000);
- bcm43xx_calc_nrssi_slope(bcm);
- } 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)
-{
- int i;
- u16 ret = 0;
- unsigned long flags;
-
- local_irq_save(flags);
- 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);
- }
- local_irq_restore(flags);
- bcm43xx_voluntary_preempt();
-
- return ret;
-}
-
-void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- 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 == 0x2053) {
- 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)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- u16 ret;
- unsigned long flags;
-
- local_irq_save(flags);
- if (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);
- }
- ret = bcm43xx_phy_read(bcm, 0x002D);
- local_irq_restore(flags);
- bcm43xx_voluntary_preempt();
-
- return ret;
-}
-
-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 - bcm43xx_current_phy(bcm)->_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 = bcm43xx_current_phy(bcm);
-
- if (baseband_attenuation > 6)
- baseband_attenuation = 6;
- assert(radio_attenuation < 10);
-
- 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)
-{
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
-
- return bcm43xx_find_lopair(bcm,
- radio->baseband_atten,
- radio->radio_atten,
- radio->txctl1);
-}
-
-/* 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 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;
-
- 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;
- }
- }
- radio->txctl2 = 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)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- u16 value;
-
- if (phy->analog == 0) {
- value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0);
- value |= (baseband_attenuation & 0x000F);
- bcm43xx_write16(bcm, 0x03E6, value);
- return;
- }
-
- if (phy->analog > 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_status(bcm) == BCM43xx_STAT_INITIALIZING);
- 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;
- 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->txctl2);
- udelay(10);
- bcm43xx_voluntary_preempt();
-
- 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->txctl2
- | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
- udelay(10);
- bcm43xx_voluntary_preempt();
-
- 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);
- bcm43xx_voluntary_preempt();
- } 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 = bcm43xx_current_phy(bcm);
- 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 = bcm43xx_current_phy(bcm);
- 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 = bcm43xx_current_radio(bcm);
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-
- 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
- */
-
- 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)) {
- bcm43xx_phy_lo_mark_current_used(bcm);
- return;
- }
-
- /* Calculate the new attenuation values. */
- baseband_attenuation = radio->baseband_atten;
- baseband_attenuation += baseband_att_delta;
- radio_attenuation = radio->radio_atten;
- 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->txctl1;
- 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->txctl1 = 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 = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- 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");
- kfree(dyn_tssi2dbm);
- 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 = bcm43xx_current_phy(bcm);
- int err = -ENODEV;
-
- 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;
- }
- 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 = bcm43xx_current_phy(bcm);
- 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;
-}
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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 <linux/types.h>
-
-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)
-
-/* Card uses the loopback gain stuff */
-#define has_loopback_gain(phy) \
- (((phy)->rev > 1) || ((phy)->connected))
-
-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_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- PIO Transmission
-
- Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
-
- 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 "bcm43xx_xmit.h"
-#include "bcm43xx_power.h"
-
-#include <linux/delay.h>
-
-
-static void tx_start(struct bcm43xx_pioqueue *queue)
-{
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_INIT);
-}
-
-static void tx_octet(struct bcm43xx_pioqueue *queue,
- u8 octet)
-{
- if (queue->need_workarounds) {
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
- octet);
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_WRITELO);
- } else {
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_WRITELO);
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
- octet);
- }
-}
-
-static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr,
- const u8 *packet,
- unsigned int *pos)
-{
- const u8 *source;
- unsigned int i = *pos;
- u16 ret;
-
- if (i < sizeof(*txhdr)) {
- source = (const u8 *)txhdr;
- } else {
- source = packet;
- i -= sizeof(*txhdr);
- }
- ret = le16_to_cpu( *((__le16 *)(source + i)) );
- *pos += 2;
-
- return ret;
-}
-
-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->need_workarounds) {
- data = tx_get_next_word(txhdr, packet, &i);
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
- }
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- 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 - sizeof(*txhdr) - 1]);
-}
-
-static void tx_complete(struct bcm43xx_pioqueue *queue,
- struct sk_buff *skb)
-{
- 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_WRITELO |
- BCM43xx_PIO_TXCTL_COMPLETE);
- } else {
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_COMPLETE);
- }
-}
-
-static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
- struct bcm43xx_pio_txpacket *packet)
-{
- u16 cookie = 0x0000;
- int packetindex;
-
- /* 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) {
- 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;
- default:
- assert(0);
- }
- packetindex = pio_txpacket_getindex(packet);
- assert(((u16)packetindex & 0xF000) == 0x0000);
- cookie |= (u16)packetindex;
-
- return cookie;
-}
-
-static
-struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm,
- u16 cookie,
- struct bcm43xx_pio_txpacket **packet)
-{
- struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm);
- struct bcm43xx_pioqueue *queue = NULL;
- int packetindex;
-
- switch (cookie & 0xF000) {
- case 0x0000:
- queue = pio->queue0;
- break;
- case 0x1000:
- queue = pio->queue1;
- break;
- case 0x2000:
- queue = pio->queue2;
- break;
- case 0x3000:
- queue = 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 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);
- bcm43xx_generate_txhdr(queue->bcm,
- &txhdr, skb->data, skb->len,
- (packet->xmitted_frags == 0),
- generate_cookie(queue, packet));
-
- tx_start(queue);
- octets = skb->len + sizeof(txhdr);
- if (queue->need_workarounds)
- octets--;
- tx_data(queue, &txhdr, (u8 *)skb->data, octets);
- tx_complete(queue, skb);
-}
-
-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;
- 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 tasklet
- * 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 tx_tasklet(unsigned long 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;
- u16 txctl;
-
- spin_lock_irqsave(&bcm->irq_lock, flags);
-
- if (queue->tx_frozen)
- goto out_unlock;
- txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
- if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
- goto out_unlock;
-
- 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, 1);
- goto next_packet;
- }
- }
- }
- /* Try to transmit the packet.
- * This may not completely succeed.
- */
- err = pio_tx_packet(packet);
- if (err)
- break;
- next_packet:
- continue;
- }
-out_unlock:
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
-}
-
-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 = 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 = kzalloc(sizeof(*queue), GFP_KERNEL);
- if (!queue)
- goto out;
-
- 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);
- tasklet_init(&queue->txtask, tx_tasklet,
- (unsigned long)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 == 0) {
- printk(KERN_ERR PFX "ERROR: This card does not support PIO "
- "operation mode. Please use DMA mode "
- "(module parameter pio=0).\n");
- goto err_freequeue;
- }
- if (qsize <= BCM43xx_PIO_TXQADJUST) {
- printk(KERN_ERR PFX "PIO tx device-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);
- tasklet_disable(&queue->txtask);
-
- list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
- free_txpacket(packet, 0);
- list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
- free_txpacket(packet, 0);
-}
-
-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)
-{
- struct bcm43xx_pio *pio;
-
- if (!bcm43xx_using_pio(bcm))
- return;
- pio = bcm43xx_current_pio(bcm);
-
- 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 = bcm43xx_current_pio(bcm);
- struct bcm43xx_pioqueue *queue;
- int err = -ENOMEM;
-
- queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE);
- if (!queue)
- goto out;
- pio->queue0 = queue;
-
- queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE);
- if (!queue)
- goto err_destroy0;
- pio->queue1 = queue;
-
- queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE);
- if (!queue)
- goto err_destroy1;
- pio->queue2 = queue;
-
- queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE);
- if (!queue)
- goto err_destroy2;
- 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(pio->queue2);
- pio->queue2 = NULL;
-err_destroy1:
- bcm43xx_destroy_pioqueue(pio->queue1);
- pio->queue1 = NULL;
-err_destroy0:
- bcm43xx_destroy_pioqueue(pio->queue0);
- pio->queue0 = NULL;
- goto out;
-}
-
-int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
- struct ieee80211_txb *txb)
-{
- struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1;
- struct bcm43xx_pio_txpacket *packet;
-
- assert(!queue->tx_suspended);
- assert(!list_empty(&queue->txfree));
-
- packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
- packet->txb = txb;
- 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 (list_empty(&queue->txfree)) {
- netif_stop_queue(queue->bcm->net_dev);
- queue->tx_suspended = 1;
- }
-
- tasklet_schedule(&queue->txtask);
-
- return 0;
-}
-
-void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
- struct bcm43xx_xmitstatus *status)
-{
- struct bcm43xx_pioqueue *queue;
- struct bcm43xx_pio_txpacket *packet;
-
- queue = parse_cookie(bcm, status->cookie, &packet);
- assert(queue);
-
- free_txpacket(packet, 1);
- if (queue->tx_suspended) {
- queue->tx_suspended = 0;
- netif_wake_queue(queue->bcm->net_dev);
- }
- /* If there are packets on the txqueue, poke the tasklet
- * to transmit them.
- */
- if (!list_empty(&queue->txqueue))
- tasklet_schedule(&queue->txtask);
-}
-
-static void pio_rx_error(struct bcm43xx_pioqueue *queue,
- int clear_buffers,
- const char *error)
-{
- 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 bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
-{
- __le16 preamble[21] = { 0 };
- struct bcm43xx_rxhdr *rxhdr;
- u16 tmp, len, rxflags2;
- int i, preamble_readwords;
- struct sk_buff *skb;
-
- tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
- if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE))
- 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 = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
- if (unlikely(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, 0, "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_le16(tmp);
- }
- rxhdr = (struct bcm43xx_rxhdr *)preamble;
- 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;
- }
- if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) {
- /* 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;
- }
-
- skb = dev_alloc_skb(len);
- if (unlikely(!skb)) {
- pio_rx_error(queue, 1, "OOM");
- return;
- }
- skb_put(skb, len);
- for (i = 0; i < len - 1; i += 2) {
- tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
- *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
- }
- if (len % 2) {
- tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
- skb->data[len - 1] = (tmp & 0x00FF);
-/* The specs say the following is required, but
- * it is wrong and corrupts the PLCP. If we don't do
- * this, the PLCP seems to be correct. So ifdef it out for now.
- */
-#if 0
- if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME)
- skb->data[2] = (tmp & 0xFF00) >> 8;
- else
- skb->data[0] = (tmp & 0xFF00) >> 8;
-#endif
- }
- skb_trim(skb, len - IEEE80211_FCS_LEN);
- bcm43xx_rx(queue->bcm, skb, rxhdr);
-}
-
-void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue)
-{
- bcm43xx_power_saving_ctl_bits(queue->bcm, -1, 1);
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
- | BCM43xx_PIO_TXCTL_SUSPEND);
-}
-
-void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
-{
- bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
- & ~BCM43xx_PIO_TXCTL_SUSPEND);
- bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1);
- if (!list_empty(&queue->txqueue))
- tasklet_schedule(&queue->txtask);
-}
-
-void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_pio *pio;
-
- assert(bcm43xx_using_pio(bcm));
- pio = bcm43xx_current_pio(bcm);
- pio->queue0->tx_frozen = 1;
- pio->queue1->tx_frozen = 1;
- pio->queue2->tx_frozen = 1;
- pio->queue3->tx_frozen = 1;
-}
-
-void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_pio *pio;
-
- assert(bcm43xx_using_pio(bcm));
- pio = bcm43xx_current_pio(bcm);
- pio->queue0->tx_frozen = 0;
- pio->queue1->tx_frozen = 0;
- pio->queue2->tx_frozen = 0;
- pio->queue3->tx_frozen = 0;
- if (!list_empty(&pio->queue0->txqueue))
- tasklet_schedule(&pio->queue0->txtask);
- if (!list_empty(&pio->queue1->txqueue))
- tasklet_schedule(&pio->queue1->txtask);
- if (!list_empty(&pio->queue2->txqueue))
- tasklet_schedule(&pio->queue2->txtask);
- if (!list_empty(&pio->queue3->txqueue))
- tasklet_schedule(&pio->queue3->txtask);
-}
-
-
+++ /dev/null
-#ifndef BCM43xx_PIO_H_
-#define BCM43xx_PIO_H_
-
-#include "bcm43xx.h"
-
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/skbuff.h>
-
-
-#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_WRITELO (1 << 0)
-#define BCM43xx_PIO_TXCTL_WRITEHI (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
-
-
-
-#ifdef CONFIG_BCM43XX_PIO
-
-
-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,
- tx_frozen:1,
- need_workarounds:1; /* Workarounds needed for core.rev < 3 */
-
- /* 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;
- unsigned int nr_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;
- /* 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);
- mmiowb();
-}
-
-
-int bcm43xx_pio_init(struct bcm43xx_private *bcm);
-void bcm43xx_pio_free(struct bcm43xx_private *bcm);
-
-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);
-
-/* Suspend a TX queue on hardware level. */
-void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue);
-void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue);
-/* Suspend (freeze) the TX tasklet (software level). */
-void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm);
-void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm);
-
-#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)
-{
-}
-static inline
-void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue)
-{
-}
-static inline
-void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
-{
-}
-static inline
-void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
-{
-}
-static inline
-void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
-{
-}
-
-#endif /* CONFIG_BCM43XX_PIO */
-#endif /* BCM43xx_PIO_H_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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 <linux/delay.h>
-
-#include "bcm43xx.h"
-#include "bcm43xx_power.h"
-#include "bcm43xx_main.h"
-
-
-/* Get the Slow Clock Source */
-static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm)
-{
- u32 tmp;
- int err;
-
- assert(bcm->current_core == &bcm->core_chipcommon);
- if (bcm->current_core->rev < 6) {
- if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA ||
- bcm->bustype == BCM43xx_BUSTYPE_SB)
- return BCM43xx_PCTL_CLKSRC_XTALOS;
- if (bcm->bustype == BCM43xx_BUSTYPE_PCI) {
- err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
- assert(!err);
- if (tmp & 0x10)
- return BCM43xx_PCTL_CLKSRC_PCI;
- return BCM43xx_PCTL_CLKSRC_XTALOS;
- }
- }
- if (bcm->current_core->rev < 10) {
- tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
- tmp &= 0x7;
- if (tmp == 0)
- return BCM43xx_PCTL_CLKSRC_LOPWROS;
- if (tmp == 1)
- return BCM43xx_PCTL_CLKSRC_XTALOS;
- if (tmp == 2)
- return BCM43xx_PCTL_CLKSRC_PCI;
- }
-
- return BCM43xx_PCTL_CLKSRC_XTALOS;
-}
-
-/* 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;
- int clocksrc;
- int divisor;
- u32 tmp;
-
- assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL);
- assert(bcm->current_core == &bcm->core_chipcommon);
-
- clocksrc = bcm43xx_pctl_get_slowclksrc(bcm);
- if (bcm->current_core->rev < 6) {
- switch (clocksrc) {
- case BCM43xx_PCTL_CLKSRC_PCI:
- divisor = 64;
- break;
- case BCM43xx_PCTL_CLKSRC_XTALOS:
- divisor = 32;
- break;
- default:
- assert(0);
- divisor = 1;
- }
- } else if (bcm->current_core->rev < 10) {
- switch (clocksrc) {
- case BCM43xx_PCTL_CLKSRC_LOPWROS:
- divisor = 1;
- break;
- case BCM43xx_PCTL_CLKSRC_XTALOS:
- case BCM43xx_PCTL_CLKSRC_PCI:
- tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
- divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
- divisor *= 4;
- break;
- default:
- assert(0);
- divisor = 1;
- }
- } else {
- tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
- divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
- divisor *= 4;
- }
-
- switch (clocksrc) {
- case BCM43xx_PCTL_CLKSRC_LOPWROS:
- if (get_max)
- limit = 43000;
- else
- limit = 25000;
- break;
- case BCM43xx_PCTL_CLKSRC_XTALOS:
- if (get_max)
- limit = 20200000;
- else
- limit = 19800000;
- break;
- case BCM43xx_PCTL_CLKSRC_PCI:
- if (get_max)
- limit = 34000000;
- else
- limit = 25000000;
- break;
- default:
- assert(0);
- limit = 0;
- }
- limit /= divisor;
-
- 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;
-
- old_core = bcm->current_core;
- err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
- if (err == -ENODEV)
- return 0;
- if (err)
- goto out;
-
- if (bcm->chip_id == 0x4321) {
- if (bcm->chip_rev == 0)
- bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x03A4);
- if (bcm->chip_rev == 1)
- bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x00A4);
- }
-
- if (bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) {
- if (bcm->current_core->rev >= 10) {
- /* Set Idle Power clock rate to 1Mhz */
- bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL,
- (bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL)
- & 0x0000FFFF) | 0x40000);
- } else {
- 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);
- }
- }
-}
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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 <linux/types.h>
-
-/* Clock sources */
-enum {
- /* PCI clock */
- BCM43xx_PCTL_CLKSRC_PCI,
- /* Crystal slow clock oscillator */
- BCM43xx_PCTL_CLKSRC_XTALOS,
- /* Low power oscillator */
- BCM43xx_PCTL_CLKSRC_LOPWROS,
-};
-
-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_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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 <linux/delay.h>
-
-#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);
- mmiowb();
- 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);
- mmiowb();
-}
-
-u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
-
- 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);
- mmiowb();
- 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 = bcm43xx_current_phy(bcm);
- 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_write(bcm, offset + i, first);
-
- for (i = start; i < end; i++)
- bcm43xx_ilt_write(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 = bcm43xx_current_phy(bcm);
- 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_write(bcm, offset + i, tmp);
- }
-
- for (i = start; i < end; i++)
- bcm43xx_ilt_write(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 = bcm43xx_current_radio(bcm);
-
- 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 = bcm43xx_current_radio(bcm);
- 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 = 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;
- 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);
- mmiowb();
- 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)
-{
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- s16 i, delta;
- s32 tmp;
-
- delta = 0x1F - radio->nrssi[0];
- for (i = 0; i < 64; i++) {
- tmp = (i - delta) * radio->nrssislope;
- tmp /= 0x10000;
- tmp += 0x3A;
- tmp = limit_value(tmp, 0, 0x3F);
- radio->nrssi_lt[i] = tmp;
- }
-}
-
-static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- 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->analog == 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_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)
- & 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 = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- 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->analog >= 2) {
- bcm43xx_write16(bcm, 0x03E6, 0x0040);
- } else if (phy->analog == 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->analog != 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:
- 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->analog >= 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, 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]);
- 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 = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- s32 threshold;
- s32 a, b;
- s16 tmp16;
- u16 tmp_u16;
-
- switch (phy->type) {
- case BCM43xx_PHYTYPE_B: {
- if (radio->version != 0x2050)
- return;
- if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI))
- return;
-
- 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;
-
- threshold = limit_value(threshold, 0, 0x3E);
- bcm43xx_phy_read(bcm, 0x0020); /* dummy read */
- bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C);
-
- if (radio->revision >= 6) {
- 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 {
- 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 = 0xE;
- b = 0x11;
- }
-
- 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)b & 0x0000003F);
- tmp_u16 |= (((u32)a & 0x0000003F) << 6);
- bcm43xx_phy_write(bcm, 0x048A, tmp_u16);
- }
- break;
- default:
- assert(0);
- }
-}
-
-/* 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 & 0xE000) == 0x0000);
- assert((id & 0xF8) == 0x00);
- *stackptr = offset;
- *stackptr |= ((u32)id) << 13;
- *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 & 0xE000) == 0x0000);
- assert((id & 0xF8) == 0x00);
- for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) {
- if ((*stackptr & 0x00001FFF) != offset)
- continue;
- if (((*stackptr & 0x00007000) >> 13) != id)
- continue;
- return ((*stackptr & 0xFFFF0000) >> 16);
- }
- assert(0);
-
- return 0;
-}
-
-#define phy_stacksave(offset) \
- do { \
- _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)
-
-static void
-bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm,
- int mode)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- 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_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 < 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);
-
- 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);
-
- phy_stacksave(0x04A0);
- bcm43xx_phy_write(bcm, 0x04A0,
- (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008);
- phy_stacksave(0x04A1);
- bcm43xx_phy_write(bcm, 0x04A1,
- (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605);
- phy_stacksave(0x04A2);
- bcm43xx_phy_write(bcm, 0x04A2,
- (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204);
- phy_stacksave(0x04A8);
- bcm43xx_phy_write(bcm, 0x04A8,
- (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803);
- phy_stacksave(0x04AB);
- bcm43xx_phy_write(bcm, 0x04AB,
- (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605);
-
- phy_stacksave(0x04A7);
- bcm43xx_phy_write(bcm, 0x04A7, 0x0002);
- phy_stacksave(0x04A3);
- bcm43xx_phy_write(bcm, 0x04A3, 0x287A);
- phy_stacksave(0x04A9);
- bcm43xx_phy_write(bcm, 0x04A9, 0x2027);
- phy_stacksave(0x0493);
- bcm43xx_phy_write(bcm, 0x0493, 0x32F5);
- phy_stacksave(0x04AA);
- bcm43xx_phy_write(bcm, 0x04AA, 0x2027);
- phy_stacksave(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;
-
- phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD);
- phy_stacksave(BCM43xx_PHY_G_CRS);
- if (phy->rev < 2) {
- phy_stacksave(0x0406);
- } else {
- phy_stacksave(0x04C0);
- phy_stacksave(0x04C1);
- }
- 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)
- & ~0x1000);
- bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
- (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
- & 0xFFFC) | 0x0002);
-
- 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);
- 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_write(bcm, 0x04A1,
- (bcm43xx_phy_read(bcm, 0x04A1)
- & 0xFFC0) | 0x0015);
- 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) | 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:
- assert(0);
- }
-}
-
-static void
-bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm,
- int mode)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u32 tmp32;
- 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_write(bcm, BCM43xx_PHY_G_CRS,
- bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000);
- break;
- }
- phy_stackrestore(0x0078);
- bcm43xx_calc_nrssi_threshold(bcm);
- phy_stackrestore(0x0406);
- 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);
- 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))
- break;
-
- radio->aci_enable = 0;
-
- 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_calc_nrssi_slope(bcm);
- break;
- default:
- assert(0);
- }
-}
-
-#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)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- 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;
-}
-
-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;
-}
-
-#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
-static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u16 loop_or = 0;
- u16 adj_loopback_gain = phy->loopback_gain[0];
- u8 loop;
- u16 extern_lna_control;
-
- if (!phy->connected)
- return 0;
- if (!has_loopback_gain(phy)) {
- if (phy->rev < 7 || !(bcm->sprom.boardflags
- & BCM43xx_BFL_EXTLNA)) {
- switch (lpd) {
- case LPD(0, 1, 1):
- return 0x0FB2;
- case LPD(0, 0, 1):
- return 0x00B2;
- case LPD(1, 0, 1):
- return 0x30B2;
- case LPD(1, 0, 0):
- return 0x30B3;
- default:
- assert(0);
- }
- } else {
- switch (lpd) {
- case LPD(0, 1, 1):
- return 0x8FB2;
- case LPD(0, 0, 1):
- return 0x80B2;
- case LPD(1, 0, 1):
- return 0x20B2;
- case LPD(1, 0, 0):
- return 0x20B3;
- default:
- assert(0);
- }
- }
- } else {
- if (radio->revision == 8)
- adj_loopback_gain += 0x003E;
- else
- adj_loopback_gain += 0x0026;
- if (adj_loopback_gain >= 0x46) {
- adj_loopback_gain -= 0x46;
- extern_lna_control = 0x3000;
- } else if (adj_loopback_gain >= 0x3A) {
- adj_loopback_gain -= 0x3A;
- extern_lna_control = 0x2000;
- } else if (adj_loopback_gain >= 0x2E) {
- adj_loopback_gain -= 0x2E;
- extern_lna_control = 0x1000;
- } else {
- adj_loopback_gain -= 0x10;
- extern_lna_control = 0x0000;
- }
- for (loop = 0; loop < 16; loop++) {
- u16 tmp = adj_loopback_gain - 6 * loop;
- if (tmp < 6)
- break;
- }
-
- loop_or = (loop << 8) | extern_lna_control;
- if (phy->rev >= 7 && bcm->sprom.boardflags
- & BCM43xx_BFL_EXTLNA) {
- if (extern_lna_control)
- loop_or |= 0x8000;
- switch (lpd) {
- case LPD(0, 1, 1):
- return 0x8F92;
- case LPD(0, 0, 1):
- return (0x8092 | loop_or);
- case LPD(1, 0, 1):
- return (0x2092 | loop_or);
- case LPD(1, 0, 0):
- return (0x2093 | loop_or);
- default:
- assert(0);
- }
- } else {
- switch (lpd) {
- case LPD(0, 1, 1):
- return 0x0F92;
- case LPD(0, 0, 1):
- case LPD(1, 0, 1):
- return (0x0092 | loop_or);
- case LPD(1, 0, 0):
- return (0x0093 | loop_or);
- default:
- assert(0);
- }
- }
- }
- return 0;
-}
-
-u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u16 backup[21] = { 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));
- if (phy->rev > 1) { /* loopback gain enabled */
- backup[19] = bcm43xx_phy_read(bcm, 0x080F);
- backup[20] = bcm43xx_phy_read(bcm, 0x0810);
- 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, 0x0812,
- bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
- if (phy->rev < 7 || !(bcm->sprom.boardflags
- & BCM43xx_BFL_EXTLNA))
- bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
- else
- bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
- }
- }
- 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->analog == 0) {
- bcm43xx_write16(bcm, 0x03E6, 0x0122);
- } else {
- if (phy->analog >= 2)
- bcm43xx_phy_write(bcm, 0x0003,
- (bcm43xx_phy_read(bcm, 0x0003)
- & 0xFFBF) | 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, 0x0026);
-
- if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812,
- bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
- bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
- bcm43xx_phy_write(bcm, 0x002B, 0x1403);
- if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812,
- bcm43xx_get_812_value(bcm, LPD(0, 0, 1)));
- bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
- bcm43xx_radio_write16(bcm, 0x0051,
- (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
- if (radio->revision == 8)
- bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
- else {
- bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
- bcm43xx_radio_write16(bcm, 0x0043,
- (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
- | 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,
- bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
- bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
- udelay(10);
- if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812,
- bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
- bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
- udelay(10);
- if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812,
- bcm43xx_get_812_value(bcm, LPD(1, 0, 0)));
- bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
- udelay(20);
- tmp1 += bcm43xx_phy_read(bcm, 0x002D);
- bcm43xx_phy_write(bcm, 0x0058, 0x0000);
- if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812,
- bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
- 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,
- bcm43xx_get_812_value(bcm,
- LPD(1, 0, 1)));
- bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
- udelay(10);
- if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812,
- bcm43xx_get_812_value(bcm,
- LPD(1, 0, 1)));
- bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
- udelay(10);
- if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812,
- bcm43xx_get_812_value(bcm,
- LPD(1, 0, 0)));
- 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,
- bcm43xx_get_812_value(bcm,
- LPD(1, 0, 1)));
- 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->analog != 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 {
- if (phy->connected) {
- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
- (bcm43xx_read16(bcm,
- BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
- 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 (phy->rev > 1) {
- bcm43xx_phy_write(bcm, 0x080F, backup[19]);
- bcm43xx_phy_write(bcm, 0x0810, backup[20]);
- }
- }
- }
- 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] | 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 = bcm43xx_current_radio(bcm);
- u16 r8, tmp;
- u16 freq;
-
- if (!ieee80211_is_valid_channel(bcm->ieee, channel))
- return -EINVAL;
- if ((radio->manufact == 0x17F) &&
- (radio->version == 0x2060) &&
- (radio->revision == 1)) {
- 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 (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)
-{
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- 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_read(bcm, 0x3001);
- ilt &= 0x0007;
-
- dac = bcm43xx_get_txgain_dac(txpower);
- dac <<= 3;
- dac |= ilt;
-
- bcm43xx_ilt_write(bcm, 0x3001, dac);
-
- radio->txpwr_offset = 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 = bcm43xx_current_radio(bcm);
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-
- if (baseband_attenuation == 0xFFFF)
- baseband_attenuation = radio->baseband_atten;
- if (radio_attenuation == 0xFFFF)
- radio_attenuation = radio->radio_atten;
- if (txpower == 0xFFFF)
- 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)
- 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) & ~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)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- 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");
- bcm43xx_leds_update(bcm, 0);
-}
-
-void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
-{
- 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);
- 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 initialized\n");
- bcm43xx_leds_update(bcm, 0);
-}
-
-void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
-{
- 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);
- 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;
- }
-}
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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);
-
-static inline
-int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm)
-{
- /* function to return state of hardware enable of radio
- * returns 0 if radio disabled, 1 if radio enabled
- */
- if (bcm->current_core->rev >= 3)
- return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI)
- & BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
- == 0) ? 1 : 0;
- else
- return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO)
- & BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
- == 0) ? 0 : 1;
-}
-
-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);
-
-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);
-
-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);
-u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm);
-
-#endif /* BCM43xx_RADIO_H_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- SYSFS support routines
-
- Copyright (c) 2006 Michael Buesch <mbuesch@freenet.de>
-
- 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 <linux/capability.h>
-
-
-#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 int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
-{
- int i, pos = 0;
-
- for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
- pos += snprintf(buf + pos, buf_len - pos - 1,
- "%04X", swab16(sprom[i]) & 0xFFFF);
- }
- pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
-
- return pos + 1;
-}
-
-static int hex2sprom(u16 *sprom, const char *dump, size_t len)
-{
- char tmp[5] = { 0 };
- int cnt = 0;
- unsigned long parsed;
-
- 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);
- }
-
- return 0;
-}
-
-static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bcm43xx_private *bcm = dev_to_bcm(dev);
- u16 *sprom;
- unsigned long flags;
- int 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;
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- err = bcm43xx_sprom_read(bcm, sprom);
- if (!err)
- err = sprom2hex(sprom, buf, PAGE_SIZE);
- mmiowb();
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
- kfree(sprom);
-
- return err;
-}
-
-static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct bcm43xx_private *bcm = dev_to_bcm(dev);
- u16 *sprom;
- unsigned long flags;
- int err;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
- GFP_KERNEL);
- if (!sprom)
- return -ENOMEM;
- err = hex2sprom(sprom, buf, count);
- if (err)
- goto out_kfree;
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- spin_lock(&bcm->leds_lock);
- err = bcm43xx_sprom_write(bcm, sprom);
- mmiowb();
- spin_unlock(&bcm->leds_lock);
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-out_kfree:
- kfree(sprom);
-
- return err ? err : count;
-
-}
-
-static DEVICE_ATTR(sprom, 0600,
- bcm43xx_attr_sprom_show,
- bcm43xx_attr_sprom_store);
-
-static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bcm43xx_private *bcm = dev_to_bcm(dev);
- ssize_t count = 0;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- mutex_lock(&bcm->mutex);
-
- switch (bcm43xx_current_radio(bcm)->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);
- }
-
- mutex_unlock(&bcm->mutex);
-
- return 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 = dev_to_bcm(dev);
- 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;
- }
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
-
- err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
- if (err) {
- printk(KERN_ERR PFX "Interference Mitigation not "
- "supported by device\n");
- }
- mmiowb();
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- return err ? err : count;
-}
-
-static DEVICE_ATTR(interference, 0644,
- bcm43xx_attr_interfmode_show,
- bcm43xx_attr_interfmode_store);
-
-static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bcm43xx_private *bcm = dev_to_bcm(dev);
- ssize_t count;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- mutex_lock(&bcm->mutex);
-
- 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");
-
- mutex_unlock(&bcm->mutex);
-
- return 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 = dev_to_bcm(dev);
- unsigned long flags;
- int value;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- value = get_boolean(buf, count);
- if (value < 0)
- return value;
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
-
- bcm->short_preamble = !!value;
-
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(shortpreamble, 0644,
- bcm43xx_attr_preamble_show,
- bcm43xx_attr_preamble_store);
-
-static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct bcm43xx_private *bcm = dev_to_bcm(dev);
- int phytype;
- int err = -EINVAL;
-
- if (count < 1)
- goto out;
- switch (buf[0]) {
- case 'a': case 'A':
- phytype = BCM43xx_PHYTYPE_A;
- break;
- case 'b': case 'B':
- phytype = BCM43xx_PHYTYPE_B;
- break;
- case 'g': case 'G':
- phytype = BCM43xx_PHYTYPE_G;
- break;
- default:
- goto out;
- }
-
- bcm43xx_cancel_work(bcm);
- mutex_lock(&(bcm)->mutex);
- err = bcm43xx_select_wireless_core(bcm, phytype);
- if (!err)
- bcm43xx_periodic_tasks_setup(bcm);
- mutex_unlock(&(bcm)->mutex);
- if (err == -ESRCH)
- err = -ENODEV;
-
-out:
- return err ? err : count;
-}
-
-static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bcm43xx_private *bcm = dev_to_bcm(dev);
- ssize_t count = 0;
-
- mutex_lock(&(bcm)->mutex);
- switch (bcm43xx_current_phy(bcm)->type) {
- case BCM43xx_PHYTYPE_A:
- snprintf(buf, PAGE_SIZE, "A");
- break;
- case BCM43xx_PHYTYPE_B:
- snprintf(buf, PAGE_SIZE, "B");
- break;
- case BCM43xx_PHYTYPE_G:
- snprintf(buf, PAGE_SIZE, "G");
- break;
- default:
- assert(0);
- }
- mutex_unlock(&(bcm)->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(phymode, 0644,
- bcm43xx_attr_phymode_show,
- bcm43xx_attr_phymode_store);
-
-static ssize_t bcm43xx_attr_microcode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- unsigned long flags;
- struct bcm43xx_private *bcm = dev_to_bcm(dev);
- ssize_t count = 0;
- u16 status;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- mutex_lock(&(bcm)->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- status = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
- BCM43xx_UCODE_STATUS);
-
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&(bcm)->mutex);
- switch (status) {
- case 0x0000:
- count = snprintf(buf, PAGE_SIZE, "0x%.4x (invalid)\n",
- status);
- break;
- case 0x0001:
- count = snprintf(buf, PAGE_SIZE, "0x%.4x (init)\n",
- status);
- break;
- case 0x0002:
- count = snprintf(buf, PAGE_SIZE, "0x%.4x (active)\n",
- status);
- break;
- case 0x0003:
- count = snprintf(buf, PAGE_SIZE, "0x%.4x (suspended)\n",
- status);
- break;
- case 0x0004:
- count = snprintf(buf, PAGE_SIZE, "0x%.4x (asleep)\n",
- status);
- break;
- default:
- count = snprintf(buf, PAGE_SIZE, "0x%.4x (unknown)\n",
- status);
- break;
- }
-
- return count;
-}
-
-static DEVICE_ATTR(microcodestatus, 0444,
- bcm43xx_attr_microcode_show,
- NULL);
-
-int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
-{
- struct device *dev = &bcm->pci_dev->dev;
- int err;
-
- assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
-
- err = device_create_file(dev, &dev_attr_sprom);
- if (err)
- goto out;
- err = device_create_file(dev, &dev_attr_interference);
- if (err)
- goto err_remove_sprom;
- err = device_create_file(dev, &dev_attr_shortpreamble);
- if (err)
- goto err_remove_interfmode;
- err = device_create_file(dev, &dev_attr_phymode);
- if (err)
- goto err_remove_shortpreamble;
- err = device_create_file(dev, &dev_attr_microcodestatus);
- if (err)
- goto err_remove_phymode;
-
-out:
- return err;
-err_remove_phymode:
- device_remove_file(dev, &dev_attr_phymode);
-err_remove_shortpreamble:
- device_remove_file(dev, &dev_attr_shortpreamble);
-err_remove_interfmode:
- device_remove_file(dev, &dev_attr_interference);
-err_remove_sprom:
- device_remove_file(dev, &dev_attr_sprom);
- goto out;
-}
-
-void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
-{
- struct device *dev = &bcm->pci_dev->dev;
-
- device_remove_file(dev, &dev_attr_microcodestatus);
- device_remove_file(dev, &dev_attr_phymode);
- device_remove_file(dev, &dev_attr_shortpreamble);
- device_remove_file(dev, &dev_attr_interference);
- device_remove_file(dev, &dev_attr_sprom);
-}
+++ /dev/null
-#ifndef BCM43xx_SYSFS_H_
-#define BCM43xx_SYSFS_H_
-
-struct bcm43xx_private;
-
-int bcm43xx_sysfs_register(struct bcm43xx_private *bcm);
-void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm);
-
-#endif /* BCM43xx_SYSFS_H_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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 <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <net/ieee80211softmac.h>
-#include <net/ieee80211softmac_wx.h>
-#include <linux/capability.h>
-#include <linux/delay.h>
-
-#include "bcm43xx.h"
-#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. */
-#define BCM43xx_WX_VERSION 18
-
-#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);
- int i;
- struct bcm43xx_phyinfo *phy;
- char suffix[7] = { 0 };
- int have_a = 0, have_b = 0, have_g = 0;
-
- mutex_lock(&bcm->mutex);
- 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;
- break;
- case BCM43xx_PHYTYPE_G:
- have_g = 1;
- case BCM43xx_PHYTYPE_B:
- have_b = 1;
- break;
- default:
- assert(0);
- }
- }
- mutex_unlock(&bcm->mutex);
-
- 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);
- unsigned long flags;
- u8 channel;
- s8 expon;
- int freq;
- int err = -EINVAL;
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
-
- if ((data->freq.e == 0) &&
- (data->freq.m >= 0) && (data->freq.m <= 1000)) {
- channel = data->freq.m;
- freq = bcm43xx_channel_to_freq(bcm, channel);
- } else {
- freq = data->freq.m;
- expon = 6 - data->freq.e;
- while (--expon >= 0) /* scale down the frequency to MHz */
- freq /= 10;
- assert(freq > 1000);
- channel = bcm43xx_freq_to_channel(bcm, freq);
- }
- if (!ieee80211_is_valid_channel(bcm->ieee, channel))
- goto out_unlock;
- if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
- //ieee80211softmac_disassoc(softmac, $REASON);
- bcm43xx_mac_suspend(bcm);
- err = bcm43xx_radio_selectchannel(bcm, channel, 0);
- bcm43xx_mac_enable(bcm);
- } else {
- bcm43xx_current_radio(bcm)->initial_channel = channel;
- err = 0;
- }
-out_unlock:
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- 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);
- struct bcm43xx_radioinfo *radio;
- int err = -ENODEV;
- u16 channel;
-
- mutex_lock(&bcm->mutex);
- radio = bcm43xx_current_radio(bcm);
- channel = radio->channel;
- if (channel == 0xFF) {
- channel = 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:
- mutex_unlock(&bcm->mutex);
-
- 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;
-
- mode = data->mode;
- if (mode == IW_MODE_AUTO)
- mode = BCM43xx_INITIAL_IWMODE;
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
- if (bcm->ieee->iw_mode != mode)
- bcm43xx_set_iwmode(bcm, mode);
- } else
- bcm->ieee->iw_mode = mode;
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- 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);
-
- mutex_lock(&bcm->mutex);
- data->mode = bcm->ieee->iw_mode;
- mutex_unlock(&bcm->mutex);
-
- 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;
- int i, j;
- struct bcm43xx_phyinfo *phy;
-
- 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;
- range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
- range->max_qual.noise = 146;
- range->max_qual.updated = IW_QUAL_ALL_UPDATED;
-
- range->avg_qual.qual = 50;
- range->avg_qual.level = 0;
- range->avg_qual.noise = 0;
- range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
-
- 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 = BCM43xx_WX_VERSION;
-
- range->enc_capa = IW_ENC_CAPA_WPA |
- IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP |
- IW_ENC_CAPA_CIPHER_CCMP;
-
- mutex_lock(&bcm->mutex);
- phy = bcm43xx_current_phy(bcm);
-
- range->num_bitrates = 0;
- i = 0;
- if (phy->type == BCM43xx_PHYTYPE_A ||
- phy->type == BCM43xx_PHYTYPE_G) {
- range->num_bitrates = 8;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000;
- }
- if (phy->type == BCM43xx_PHYTYPE_B ||
- phy->type == BCM43xx_PHYTYPE_G) {
- range->num_bitrates += 4;
- range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000;
- range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000;
- range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000;
- range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000;
- }
-
- 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 * 100000;
- 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 * 100000;
- range->freq[j].e = 1;
- j++;
- }
- range->num_frequency = j;
-
- mutex_unlock(&bcm->mutex);
-
- 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);
- size_t len;
-
- mutex_lock(&bcm->mutex);
- len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
- memcpy(bcm->nick, extra, len);
- bcm->nick[len] = '\0';
- mutex_unlock(&bcm->mutex);
-
- 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);
- size_t len;
-
- mutex_lock(&bcm->mutex);
- len = strlen(bcm->nick);
- memcpy(extra, bcm->nick, len);
- data->data.length = (__u16)len;
- data->data.flags = 1;
- mutex_unlock(&bcm->mutex);
-
- 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;
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_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->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- 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);
-
- mutex_lock(&bcm->mutex);
- data->rts.value = bcm->rts_threshold;
- data->rts.fixed = 0;
- data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
- mutex_unlock(&bcm->mutex);
-
- 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;
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_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->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- 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);
-
- mutex_lock(&bcm->mutex);
- data->frag.value = bcm->ieee->fts;
- data->frag.fixed = 0;
- data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
- mutex_unlock(&bcm->mutex);
-
- 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);
- struct bcm43xx_radioinfo *radio;
- struct bcm43xx_phyinfo *phy;
- unsigned long flags;
- int err = -ENODEV;
- u16 maxpower;
-
- if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
- printk(KERN_ERR PFX "TX power not in dBm.\n");
- return -EOPNOTSUPP;
- }
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
- goto out_unlock;
- 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);
- else
- bcm43xx_radio_turn_on(bcm);
- }
- 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:
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- 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);
- struct bcm43xx_radioinfo *radio;
- int err = -ENODEV;
-
- mutex_lock(&bcm->mutex);
- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
- goto out_unlock;
- radio = bcm43xx_current_radio(bcm);
- /* 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:
- mutex_unlock(&bcm->mutex);
-
- return err;
-}
-
-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;
-
- 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;
-
- 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;
-
- 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;
-
- err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
-
- return err;
-}
-
-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;
-
- 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;
- }
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- if (bcm43xx_status(bcm) == BCM43xx_STAT_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
- bcm43xx_current_radio(bcm)->interfmode = mode;
- }
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- 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);
- int mode;
-
- mutex_lock(&bcm->mutex);
- mode = bcm43xx_current_radio(bcm)->interfmode;
- mutex_unlock(&bcm->mutex);
-
- 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;
-
- on = *((int *)extra);
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- bcm->short_preamble = !!on;
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- 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);
- int on;
-
- mutex_lock(&bcm->mutex);
- on = bcm->short_preamble;
- mutex_unlock(&bcm->mutex);
-
- 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;
-
- on = *((int *)extra);
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- bcm->ieee->host_encrypt = !!on;
- bcm->ieee->host_decrypt = !!on;
- bcm->ieee->host_build_iv = !on;
- bcm->ieee->host_strip_iv_icv = !on;
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-
- 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);
- int on;
-
- mutex_lock(&bcm->mutex);
- on = bcm->ieee->host_encrypt;
- mutex_unlock(&bcm->mutex);
-
- 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;
-
- 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);
- }
-
- 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;
- 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;
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- err = -ENODEV;
- if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
- err = bcm43xx_sprom_read(bcm, sprom);
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
- if (!err)
- data->data.length = sprom2hex(sprom, extra);
- 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;
-
- 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;
-
- mutex_lock(&bcm->mutex);
- spin_lock_irqsave(&bcm->irq_lock, flags);
- spin_lock(&bcm->leds_lock);
- err = -ENODEV;
- if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
- err = bcm43xx_sprom_write(bcm, sprom);
- spin_unlock(&bcm->leds_lock);
- spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_unlock(&bcm->mutex);
-out_kfree:
- kfree(sprom);
-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;
- struct ieee80211_network *network = NULL;
- static int tmp_level = 0;
- static int tmp_qual = 0;
- unsigned long flags;
-
- wstats = &bcm->stats.wstats;
- if (!mac->associnfo.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_ALL_UPDATED | IW_QUAL_DBM;
- return wstats;
- }
- /* fill in the real statistics when iface associated */
- spin_lock_irqsave(&mac->ieee->lock, flags);
- list_for_each_entry(network, &mac->ieee->network_list, list) {
- if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
- if (!tmp_level) { /* get initial values */
- tmp_level = network->stats.signal;
- tmp_qual = network->stats.rssi;
- } else { /* smooth results */
- tmp_level = (15 * tmp_level + network->stats.signal)/16;
- tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
- }
- break;
- }
- }
- spin_unlock_irqrestore(&mac->ieee->lock, flags);
- wstats->qual.level = tmp_level;
- wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
- wstats->qual.noise = bcm->stats.noise;
- wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- 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
-#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_shortpreamb",
- },
- {
- .cmd = PRIV_WX_GET_SHORTPREAMBLE,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
- .name = "get_shortpreamb",
- },
- {
- .cmd = PRIV_WX_SET_SWENCRYPTION,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_swencrypt",
- },
- {
- .cmd = PRIV_WX_GET_SWENCRYPTION,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
- .name = "get_swencrypt",
- },
- {
- .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,
- .get_wireless_stats = bcm43xx_get_wireless_stats,
-};
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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_ */
+++ /dev/null
-/*
-
- Broadcom BCM43xx wireless driver
-
- Transmission (TX/RX) related functions.
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- 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 <linux/etherdevice.h>
-
-
-/* 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) {
- u32 val = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
- assert(!(octets & 0xF000));
- val |= (octets << 5);
- *data = cpu_to_le32(val);
- } 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 = 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;
- 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;
- const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
- const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
-
- /* Now construct the TX header. */
- memset(txhdr, 0, sizeof(*txhdr));
-
- bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
- is_multicast_ether_addr(wireless_header->addr1), is_mgt);
- 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 = bcm43xx_current_radio(bcm);
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- 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;
-}
-
-//TODO
-#if 0
-static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
- u8 in_rssi)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- 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;
-}
-#endif
-
-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;
- 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 = rxhdr->rssi;
- stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
- !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
- !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
- stats.noise = bcm->stats.noise;
- if (is_ofdm)
- stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
- else
- stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
- stats.received_channel = radio->channel;
- stats.mask = IEEE80211_STATMASK_SIGNAL |
- IEEE80211_STATMASK_NOISE |
- IEEE80211_STATMASK_RATE |
- IEEE80211_STATMASK_RSSI;
- if (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);
- 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;
-}
+++ /dev/null
-#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 explicitly 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_AMPDU 0x10
-#define BCM43xx_TXSTAT_FLAG_INTER 0x20
-
-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_ */
remaining_bytes,
PCI_DMA_TODEVICE));
- tfd->u.data.num_chunks =
- cpu_to_le32(le32_to_cpu(tfd->u.data.num_chunks) +
- 1);
+ le32_add_cpu(&tfd->u.data.num_chunks, 1);
}
}
+config IWLCORE
+ tristate "Intel Wireless Wifi Core"
+ depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+
config IWL4965
tristate "Intel Wireless WiFi 4965AGN"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
+ select IWLCORE
---help---
Select to build the driver supporting the:
say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwl4965.ko.
-config IWL4965_QOS
- bool "Enable Wireless QoS in iwl4965 driver"
- depends on IWL4965
- ---help---
- This option will enable wireless quality of service (QoS) for the
- iwl4965 driver.
-
config IWL4965_HT
bool "Enable 802.11n HT features in iwl4965 driver"
depends on EXPERIMENTAL
- depends on IWL4965 && IWL4965_QOS
- depends on n
+ depends on IWL4965
---help---
This option enables IEEE 802.11n High Throughput features
for the iwl4965 driver.
say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwl3945.ko.
-config IWL3945_QOS
- bool "Enable Wireless QoS in iwl3945 driver"
- depends on IWL3945
- ---help---
- This option will enable wireless quality of service (QoS) for the
- iwl3945 driver.
-
config IWL3945_SPECTRUM_MEASUREMENT
bool "Enable Spectrum Measurement in iwl3945 drivers"
depends on IWL3945
+obj-$(CONFIG_IWLCORE) += iwlcore.o
+iwlcore-objs = iwl-core.o iwl-eeprom.o
+
obj-$(CONFIG_IWL3945) += iwl3945.o
iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#define STA_CONTROL_MODIFY_MSK 0x01
/* key flags __le16*/
-#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7)
-#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0)
-#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1)
-#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2)
-#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3)
+#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007)
+#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000)
+#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001)
+#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002)
+#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003)
#define STA_KEY_FLG_KEYID_POS 8
#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800)
+/* wep key is either from global key (0) or from station info array (1) */
+#define STA_KEY_FLG_WEP_KEY_MAP_MSK __constant_cpu_to_le16(0x0008)
+
+/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
+#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000)
+#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000)
/* Flags indicate whether to modify vs. don't change various station params */
#define STA_MODIFY_KEY_MASK 0x01
u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */
u8 reserved1;
__le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
- __le16 reserved2;
+ u8 key_offset;
+ u8 reserved2;
u8 key[16]; /* 16-byte unicast decryption key */
} __attribute__ ((packed));
u8 payload[0];
} __attribute__ ((packed));
-#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1)
-
-#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0)
-
-#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
-#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
-#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8)
-#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8)
-#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8)
-
-#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
-#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11)
-#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11)
-#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11)
-#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11)
+#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1)
+
+#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0)
+
+#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
+#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
+#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8)
+#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8)
+#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8)
+
+#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
+#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11)
+#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11)
+#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11)
+#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11)
struct iwl3945_rx_frame_end {
__le32 status;
--- /dev/null
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_3945_dev_h__
+#define __iwl_3945_dev_h__
+
+#define IWL_PCI_DEVICE(dev, subdev, cfg) \
+ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
+ .subvendor = PCI_ANY_ID, .subdevice = (subdev), \
+ .driver_data = (kernel_ulong_t)&(cfg)
+
+#define IWL_SKU_G 0x1
+#define IWL_SKU_A 0x2
+
+struct iwl_3945_cfg {
+ const char *name;
+ const char *fw_name;
+ unsigned int sku;
+};
+
+#endif /* __iwl_dev_h__ */
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \
printk(KERN_ERR DRV_NAME": %c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+static inline void iwl3945_print_hex_dump(int level, void *p, u32 len)
+{
+ if (!(iwl3945_debug_level & level))
+ return;
+
+ print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+ p, len, 1);
+}
#else
static inline void IWL_DEBUG(int level, const char *fmt, ...)
{
static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
{
}
-#endif /* CONFIG_IWL3945_DEBUG */
+static inline void iwl3945_print_hex_dump(int level, void *p, u32 len)
+{
+}
+#endif /* CONFIG_IWL3945_DEBUG */
+
+
/*
* To use the debug system;
IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a)
#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
+#define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a)
#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
#define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a)
#define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a)
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#define PCI_REG_WUM8 0x0E8
#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
-/*=== CSR (control and status registers) ===*/
-#define CSR_BASE (0x000)
-
-#define CSR_SW_VER (CSR_BASE+0x000)
-#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
-#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
-#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */
-#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */
-#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/
-#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */
-#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
-#define CSR_GP_CNTRL (CSR_BASE+0x024)
-
-/*
- * Hardware revision info
- * Bit fields:
- * 31-8: Reserved
- * 7-4: Type of device: 0x0 = 4965, 0xd = 3945
- * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D
- * 1-0: "Dash" value, as in A-1, etc.
- */
-#define CSR_HW_REV (CSR_BASE+0x028)
-
-/* EEPROM reads */
-#define CSR_EEPROM_REG (CSR_BASE+0x02c)
-#define CSR_EEPROM_GP (CSR_BASE+0x030)
-#define CSR_GP_UCODE (CSR_BASE+0x044)
-#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
-#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
-#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
-#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
-#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
-
-/* Analog phase-lock-loop configuration (3945 only)
- * Set bit 24. */
-#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
-
-/* Bits for CSR_HW_IF_CONFIG_REG */
-#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100)
-#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200)
-#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400)
-#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800)
-#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
-#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)
-#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
-
-/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
- * acknowledged (reset) by host writing "1" to flagged bits. */
-#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */
-#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */
-#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */
-#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */
-#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */
-#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */
-#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */
-#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */
-#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */
-#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */
-#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */
-
-#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \
- CSR_INT_BIT_HW_ERR | \
- CSR_INT_BIT_FH_TX | \
- CSR_INT_BIT_SW_ERR | \
- CSR_INT_BIT_RF_KILL | \
- CSR_INT_BIT_SW_RX | \
- CSR_INT_BIT_WAKEUP | \
- CSR_INT_BIT_ALIVE)
-
-/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
-#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */
-#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */
-#define CSR_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */
-#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */
-#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */
-#define CSR_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */
-#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */
-#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */
-
-#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
- CSR_FH_INT_BIT_RX_CHNL2 | \
- CSR_FH_INT_BIT_RX_CHNL1 | \
- CSR_FH_INT_BIT_RX_CHNL0)
-
-#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \
- CSR_FH_INT_BIT_TX_CHNL1 | \
- CSR_FH_INT_BIT_TX_CHNL0)
-
-
-/* RESET */
-#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001)
-#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002)
-#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
-#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
-#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
-
-/* GP (general purpose) CONTROL */
-#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
-#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
-#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
-#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010)
-
-#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001)
-
-#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000)
-#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000)
-#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000)
-
-
-/* EEPROM REG */
-#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
-#define CSR_EEPROM_REG_BIT_CMD (0x00000002)
-
-/* EEPROM GP */
-#define CSR_EEPROM_GP_VALID_MSK (0x00000006)
-#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
-#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
-
-/* UCODE DRV GP */
-#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
-#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
-#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
-#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
-
-/* GPIO */
-#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200)
-#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000)
-#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER
-
-/* GI Chicken Bits */
-#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
-#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
-
-/* CSR_ANA_PLL_CFG */
-#define CSR_ANA_PLL_CFG_SH (0x00880300)
-
-/*=== HBUS (Host-side Bus) ===*/
-#define HBUS_BASE (0x400)
-
-/*
- * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
- * structures, error log, event log, verifying uCode load).
- * First write to address register, then read from or write to data register
- * to complete the job. Once the address register is set up, accesses to
- * data registers auto-increment the address by one dword.
- * Bit usage for address registers (read or write):
- * 0-31: memory address within device
- */
-#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c)
-#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010)
-#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
-#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)
-
-/*
- * Registers for accessing device's internal peripheral registers
- * (e.g. SCD, BSM, etc.). First write to address register,
- * then read from or write to data register to complete the job.
- * Bit usage for address registers (read or write):
- * 0-15: register address (offset) within device
- * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword)
- */
-#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044)
-#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048)
-#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c)
-#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
-
-/*
- * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
- * Indicates index to next TFD that driver will fill (1 past latest filled).
- * Bit usage:
- * 0-7: queue write index
- * 11-8: queue selector
- */
-#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
-
/* SCD (3945 Tx Frame Scheduler) */
#define SCD_BASE (CSR_BASE + 0x2E00)
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
*
*/
-#define _iwl3945_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#define _iwl3945_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs))
#ifdef CONFIG_IWL3945_DEBUG
-static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *iwl,
+static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *priv,
u32 ofs, u32 val)
{
IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
- _iwl3945_write32(iwl, ofs, val);
+ _iwl3945_write32(priv, ofs, val);
}
-#define iwl3945_write32(iwl, ofs, val) \
- __iwl3945_write32(__FILE__, __LINE__, iwl, ofs, val)
+#define iwl3945_write32(priv, ofs, val) \
+ __iwl3945_write32(__FILE__, __LINE__, priv, ofs, val)
#else
-#define iwl3945_write32(iwl, ofs, val) _iwl3945_write32(iwl, ofs, val)
+#define iwl3945_write32(priv, ofs, val) _iwl3945_write32(priv, ofs, val)
#endif
-#define _iwl3945_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#define _iwl3945_read32(priv, ofs) readl((priv)->hw_base + (ofs))
#ifdef CONFIG_IWL3945_DEBUG
-static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *iwl, u32 ofs)
+static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *priv, u32 ofs)
{
IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
- return _iwl3945_read32(iwl, ofs);
+ return _iwl3945_read32(priv, ofs);
}
-#define iwl3945_read32(iwl, ofs) __iwl3945_read32(__FILE__, __LINE__, iwl, ofs)
+#define iwl3945_read32(priv, ofs) __iwl3945_read32(__FILE__, __LINE__, priv, ofs)
#else
#define iwl3945_read32(p, o) _iwl3945_read32(p, o)
#endif
u32 bits, u32 mask, int timeout)
{
int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout);
- if (unlikely(ret == -ETIMEDOUT))
- IWL_DEBUG_IO
- ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
- addr, bits, mask, f, l);
- else
- IWL_DEBUG_IO
- ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
- addr, bits, mask, ret, f, l);
+ IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
+ addr, bits, mask,
+ unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l);
return ret;
}
-#define iwl3945_poll_bit(iwl, addr, bits, mask, timeout) \
- __iwl3945_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \
+ __iwl3945_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout)
#else
#define iwl3945_poll_bit(p, a, b, m, t) _iwl3945_poll_bit(p, a, b, m, t)
#endif
"- %s %d\n", addr, mask, ret, f, l);
return ret;
}
-#define iwl3945_poll_direct_bit(iwl, addr, mask, timeout) \
- __iwl3945_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#define iwl3945_poll_direct_bit(priv, addr, mask, timeout) \
+ __iwl3945_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout)
#else
#define iwl3945_poll_direct_bit _iwl3945_poll_direct_bit
#endif
/******************************************************************************
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
{-89, IWL_RATE_6M_INDEX}
};
-static struct iwl3945_tpt_entry iwl3945_tpt_table_b[] = {
- {-86, IWL_RATE_11M_INDEX},
- {-88, IWL_RATE_5M_INDEX},
- {-90, IWL_RATE_2M_INDEX},
- {-92, IWL_RATE_1M_INDEX}
-
-};
-
static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = {
{-60, IWL_RATE_54M_INDEX},
{-64, IWL_RATE_48M_INDEX},
#define IWL_RATE_MIN_SUCCESS_TH 8
#define IWL_RATE_DECREASE_TH 1920
-static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, u8 mode)
+static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, enum ieee80211_band band)
{
u32 index = 0;
u32 table_size = 0;
if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL))
rssi = IWL_MIN_RSSI_VAL;
- switch (mode) {
- case MODE_IEEE80211G:
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
tpt_table = iwl3945_tpt_table_g;
table_size = ARRAY_SIZE(iwl3945_tpt_table_g);
break;
- case MODE_IEEE80211A:
+ case IEEE80211_BAND_5GHZ:
tpt_table = iwl3945_tpt_table_a;
table_size = ARRAY_SIZE(iwl3945_tpt_table_a);
break;
default:
- case MODE_IEEE80211B:
- tpt_table = iwl3945_tpt_table_b;
- table_size = ARRAY_SIZE(iwl3945_tpt_table_b);
+ BUG();
break;
}
{
window->data = 0;
window->success_counter = 0;
- window->success_ratio = IWL_INVALID_VALUE;
+ window->success_ratio = -1;
window->counter = 0;
- window->average_tpt = IWL_INVALID_VALUE;
+ window->average_tpt = IWL_INV_TPT;
window->stamp = 0;
}
* after assoc.. */
for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
- if (sta->supp_rates & (1 << i)) {
- sta->txrate = i;
+ if (sta->supp_rates[local->hw.conf.channel->band] & (1 << i)) {
+ sta->txrate_idx = i;
break;
}
}
- sta->last_txrate = sta->txrate;
+ sta->last_txrate_idx = sta->txrate_idx;
- /* For MODE_IEEE80211A mode it start at IWL_FIRST_OFDM_RATE */
- if (local->hw.conf.phymode == MODE_IEEE80211A)
- sta->last_txrate += IWL_FIRST_OFDM_RATE;
+ /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
+ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
+ sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
IWL_DEBUG_RATE("leave\n");
}
{
int next_rate = iwl3945_get_prev_ieee_rate(rate);
- switch (priv->phymode) {
- case MODE_IEEE80211A:
+ switch (priv->band) {
+ case IEEE80211_BAND_5GHZ:
if (rate == IWL_RATE_12M_INDEX)
next_rate = IWL_RATE_9M_INDEX;
else if (rate == IWL_RATE_6M_INDEX)
next_rate = IWL_RATE_6M_INDEX;
break;
+/* XXX cannot be invoked in current mac80211 so not a regression
case MODE_IEEE80211B:
if (rate == IWL_RATE_11M_INDEX_TABLE)
next_rate = IWL_RATE_5M_INDEX_TABLE;
break;
+ */
default:
break;
}
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iwl3945_rs_sta *rs_sta;
+ struct ieee80211_supported_band *sband;
IWL_DEBUG_RATE("enter\n");
- retries = tx_resp->retry_count;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- first_index = tx_resp->control.tx_rate;
+
+ retries = tx_resp->retry_count;
+ first_index = tx_resp->control.tx_rate->hw_value;
if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
- IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n",
- tx_resp->control.tx_rate, first_index);
+ IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
return;
}
+ rcu_read_lock();
+
sta = sta_info_get(local, hdr->addr1);
if (!sta || !sta->rate_ctrl_priv) {
- if (sta)
- sta_info_put(sta);
+ rcu_read_unlock();
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
return;
}
spin_unlock_irqrestore(&rs_sta->lock, flags);
- sta_info_put(sta);
+ rcu_read_unlock();
IWL_DEBUG_RATE("leave\n");
}
static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta,
- u8 index, u16 rate_mask, int phymode)
+ u8 index, u16 rate_mask, enum ieee80211_band band)
{
u8 high = IWL_RATE_INVALID;
u8 low = IWL_RATE_INVALID;
/* 802.11A walks to the next literal adjacent rate in
* the rate table */
- if (unlikely(phymode == MODE_IEEE80211A)) {
+ if (unlikely(band == IEEE80211_BAND_5GHZ)) {
int i;
u32 mask;
*
*/
static void rs_get_rate(void *priv_rate, struct net_device *dev,
- struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+ struct ieee80211_supported_band *sband,
+ struct sk_buff *skb,
struct rate_selection *sel)
{
u8 low = IWL_RATE_INVALID;
int index;
struct iwl3945_rs_sta *rs_sta;
struct iwl3945_rate_scale_data *window = NULL;
- int current_tpt = IWL_INVALID_VALUE;
- int low_tpt = IWL_INVALID_VALUE;
- int high_tpt = IWL_INVALID_VALUE;
+ int current_tpt = IWL_INV_TPT;
+ int low_tpt = IWL_INV_TPT;
+ int high_tpt = IWL_INV_TPT;
u32 fail_count;
s8 scale_action = 0;
unsigned long flags;
IWL_DEBUG_RATE("enter\n");
+ rcu_read_lock();
+
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest
is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) {
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
- sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
- if (sta)
- sta_info_put(sta);
+ sel->rate = rate_lowest(local, sband, sta);
+ rcu_read_unlock();
return;
}
- rate_mask = sta->supp_rates;
- index = min(sta->last_txrate & 0xffff, IWL_RATE_COUNT - 1);
+ rate_mask = sta->supp_rates[sband->band];
+ index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
- if (priv->phymode == (u8) MODE_IEEE80211A)
+ if (sband->band == IEEE80211_BAND_5GHZ)
rate_mask = rate_mask << IWL_FIRST_OFDM_RATE;
rs_sta = (void *)sta->rate_ctrl_priv;
if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) &&
(window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) {
- window->average_tpt = IWL_INVALID_VALUE;
+ window->average_tpt = IWL_INV_TPT;
spin_unlock_irqrestore(&rs_sta->lock, flags);
IWL_DEBUG_RATE("Invalid average_tpt on rate %d: "
current_tpt = window->average_tpt;
high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask,
- local->hw.conf.phymode);
+ sband->band);
low = high_low & 0xff;
high = (high_low >> 8) & 0xff;
if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) {
IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
scale_action = -1;
- } else if ((low_tpt == IWL_INVALID_VALUE) &&
- (high_tpt == IWL_INVALID_VALUE))
+ } else if ((low_tpt == IWL_INV_TPT) && (high_tpt == IWL_INV_TPT))
scale_action = 1;
- else if ((low_tpt != IWL_INVALID_VALUE) &&
- (high_tpt != IWL_INVALID_VALUE)
- && (low_tpt < current_tpt)
- && (high_tpt < current_tpt)) {
+ else if ((low_tpt != IWL_INV_TPT) && (high_tpt != IWL_INV_TPT) &&
+ (low_tpt < current_tpt) && (high_tpt < current_tpt)) {
IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < "
"current_tpt [%d]\n",
low_tpt, high_tpt, current_tpt);
scale_action = 0;
} else {
- if (high_tpt != IWL_INVALID_VALUE) {
+ if (high_tpt != IWL_INV_TPT) {
if (high_tpt > current_tpt)
scale_action = 1;
else {
("decrease rate because of high tpt\n");
scale_action = -1;
}
- } else if (low_tpt != IWL_INVALID_VALUE) {
+ } else if (low_tpt != IWL_INV_TPT) {
if (low_tpt > current_tpt) {
IWL_DEBUG_RATE
("decrease rate because of low tpt\n");
out:
- sta->last_txrate = index;
- if (priv->phymode == (u8) MODE_IEEE80211A)
- sta->txrate = sta->last_txrate - IWL_FIRST_OFDM_RATE;
+ sta->last_txrate_idx = index;
+ if (sband->band == IEEE80211_BAND_5GHZ)
+ sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
else
- sta->txrate = sta->last_txrate;
+ sta->txrate_idx = sta->last_txrate_idx;
- sta_info_put(sta);
+ rcu_read_unlock();
IWL_DEBUG_RATE("leave: %d\n", index);
- sel->rate = &priv->ieee_rates[index];
+ sel->rate = &sband->bitrates[sta->txrate_idx];
}
static struct rate_control_ops rs_ops = {
unsigned long now = jiffies;
u32 max_time = 0;
+ rcu_read_lock();
+
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
- if (sta) {
- sta_info_put(sta);
+ if (sta)
IWL_DEBUG_RATE("leave - no private rate data!\n");
- } else
+ else
IWL_DEBUG_RATE("leave - no station!\n");
+ rcu_read_unlock();
return sprintf(buf, "station %d not found\n", sta_id);
}
i = j;
}
spin_unlock_irqrestore(&rs_sta->lock, flags);
- sta_info_put(sta);
+ rcu_read_unlock();
/* Display the average rate of all samples taken.
*
return;
}
+ rcu_read_lock();
+
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
- if (sta)
- sta_info_put(sta);
IWL_DEBUG_RATE("leave - no private rate data!\n");
+ rcu_read_unlock();
return;
}
spin_lock_irqsave(&rs_sta->lock, flags);
rs_sta->tgg = 0;
- switch (priv->phymode) {
- case MODE_IEEE80211G:
+ switch (priv->band) {
+ case IEEE80211_BAND_2GHZ:
+ /* TODO: this always does G, not a regression */
if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
rs_sta->tgg = 1;
rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot;
rs_sta->expected_tpt = iwl3945_expected_tpt_g;
break;
- case MODE_IEEE80211A:
+ case IEEE80211_BAND_5GHZ:
rs_sta->expected_tpt = iwl3945_expected_tpt_a;
break;
-
- default:
- IWL_WARNING("Invalid phymode. Defaulting to 802.11b\n");
- case MODE_IEEE80211B:
- rs_sta->expected_tpt = iwl3945_expected_tpt_b;
+ case IEEE80211_NUM_BANDS:
+ BUG();
break;
}
- sta_info_put(sta);
+ rcu_read_unlock();
spin_unlock_irqrestore(&rs_sta->lock, flags);
rssi = priv->last_rx_rssi;
IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi);
- rs_sta->start_rate =
- iwl3945_get_rate_index_by_rssi(rssi, priv->phymode);
+ rs_sta->start_rate = iwl3945_get_rate_index_by_rssi(rssi, priv->band);
IWL_DEBUG_RATE("leave: rssi %d assign rate index: "
"%d (plcp 0x%x)\n", rssi, rs_sta->start_rate,
/******************************************************************************
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
u8 next_rs; /* next rate used in rs algo */
u8 prev_rs_tgg; /* previous rate used in TGG rs algo */
u8 next_rs_tgg; /* next rate used in TGG rs algo */
- u8 table_rs_index; /* index in rate scale table cmd */
- u8 prev_table_rs; /* prev in rate table cmd */
+ u8 table_rs_index; /* index in rate scale table cmd */
+ u8 prev_table_rs; /* prev in rate table cmd */
};
/*
#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
-#define IWL_INVALID_VALUE -1
+#define IWL_INV_TPT -1
#define IWL_MIN_RSSI_VAL -100
#define IWL_MAX_RSSI_VAL 0
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
#include <asm/unaligned.h>
#include <net/mac80211.h>
+#include "iwl-3945-core.h"
#include "iwl-3945.h"
#include "iwl-helpers.h"
#include "iwl-3945-rs.h"
}
+static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
+{
+ int idx;
+
+ for (idx = 0; idx < IWL_RATE_COUNT; idx++)
+ if (iwl3945_rates[idx].plcp == plcp)
+ return idx;
+ return -1;
+}
+
/**
* iwl3945_get_antenna_flags - Get antenna flags for RXON command
* @priv: eeprom and antenna fields are used to determine antenna flags
return 0; /* "diversity" is default if error */
}
+#ifdef CONFIG_IWL3945_DEBUG
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static const char *iwl3945_get_tx_fail_reason(u32 status)
+{
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ return "SUCCESS";
+ TX_STATUS_ENTRY(SHORT_LIMIT);
+ TX_STATUS_ENTRY(LONG_LIMIT);
+ TX_STATUS_ENTRY(FIFO_UNDERRUN);
+ TX_STATUS_ENTRY(MGMNT_ABORT);
+ TX_STATUS_ENTRY(NEXT_FRAG);
+ TX_STATUS_ENTRY(LIFE_EXPIRE);
+ TX_STATUS_ENTRY(DEST_PS);
+ TX_STATUS_ENTRY(ABORTED);
+ TX_STATUS_ENTRY(BT_RETRY);
+ TX_STATUS_ENTRY(STA_INVALID);
+ TX_STATUS_ENTRY(FRAG_DROPPED);
+ TX_STATUS_ENTRY(TID_DISABLE);
+ TX_STATUS_ENTRY(FRAME_FLUSHED);
+ TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+ TX_STATUS_ENTRY(TX_LOCKED);
+ TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+ }
+
+ return "UNKNOWN";
+}
+#else
+static inline const char *iwl3945_get_tx_fail_reason(u32 status)
+{
+ return "";
+}
+#endif
+
+
+/**
+ * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
+ *
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms. If there is
+ * enough free space (> low mark), wake the stack that feeds us.
+ */
+static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv,
+ int txq_id, int index)
+{
+ struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl3945_queue *q = &txq->q;
+ struct iwl3945_tx_info *tx_info;
+
+ BUG_ON(txq_id == IWL_CMD_QUEUE_NUM);
+
+ for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+ tx_info = &txq->txb[txq->q.read_ptr];
+ ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0],
+ &tx_info->status);
+ tx_info->skb[0] = NULL;
+ iwl3945_hw_txq_free_tfd(priv, txq);
+ }
+
+ if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+ (txq_id != IWL_CMD_QUEUE_NUM) &&
+ priv->mac80211_registered)
+ ieee80211_wake_queue(priv->hw, txq_id);
+}
+
+/**
+ * iwl3945_rx_reply_tx - Handle Tx response
+ */
+static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
+ struct iwl3945_rx_mem_buffer *rxb)
+{
+ struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
+ struct ieee80211_tx_status *tx_status;
+ struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ u32 status = le32_to_cpu(tx_resp->status);
+ int rate_idx;
+
+ if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+ "is out of range [0-%d] %d %d\n", txq_id,
+ index, txq->q.n_bd, txq->q.write_ptr,
+ txq->q.read_ptr);
+ return;
+ }
+
+ tx_status = &(txq->txb[txq->q.read_ptr].status);
+
+ tx_status->retry_count = tx_resp->failure_frame;
+ /* tx_status->rts_retry_count = tx_resp->failure_rts; */
+ tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
+ IEEE80211_TX_STATUS_ACK : 0;
+
+ IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
+ txq_id, iwl3945_get_tx_fail_reason(status), status,
+ tx_resp->rate, tx_resp->failure_frame);
+
+ rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
+ tx_status->control.tx_rate = &priv->ieee_rates[rate_idx];
+ IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+ iwl3945_tx_queue_reclaim(priv, txq_id, index);
+
+ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+ IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+
/*****************************************************************************
*
* Intel PRO/Wireless 3945ABG/BG Network Connection
*
* RX handler implementations
*
- * Used by iwl-base.c
- *
*****************************************************************************/
void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb)
priv->last_statistics_time = jiffies;
}
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWL3945_DEBUG
+
+/**
+ * iwl3945_report_frame - dump frame to syslog during debug sessions
+ *
+ * You may hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ */
+static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
+ struct iwl3945_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100)
+{
+ u32 to_us;
+ u32 print_summary = 0;
+ u32 print_dump = 0; /* set to 1 to dump all frames' contents */
+ u32 hundred = 0;
+ u32 dataframe = 0;
+ u16 fc;
+ u16 seq_ctl;
+ u16 channel;
+ u16 phy_flags;
+ u16 length;
+ u16 status;
+ u16 bcn_tmr;
+ u32 tsf_low;
+ u64 tsf;
+ u8 rssi;
+ u8 agc;
+ u16 sig_avg;
+ u16 noise_diff;
+ struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+ struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ u8 *data = IWL_RX_DATA(pkt);
+
+ /* MAC header */
+ fc = le16_to_cpu(header->frame_control);
+ seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+ /* metadata */
+ channel = le16_to_cpu(rx_hdr->channel);
+ phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+ length = le16_to_cpu(rx_hdr->len);
+
+ /* end-of-frame status and timestamp */
+ status = le32_to_cpu(rx_end->status);
+ bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+ tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+ tsf = le64_to_cpu(rx_end->timestamp);
+
+ /* signal statistics */
+ rssi = rx_stats->rssi;
+ agc = rx_stats->agc;
+ sig_avg = le16_to_cpu(rx_stats->sig_avg);
+ noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+ to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+ /* if data frame is to us and all is good,
+ * (optionally) print summary for only 1 out of every 100 */
+ if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+ dataframe = 1;
+ if (!group100)
+ print_summary = 1; /* print each frame */
+ else if (priv->framecnt_to_us < 100) {
+ priv->framecnt_to_us++;
+ print_summary = 0;
+ } else {
+ priv->framecnt_to_us = 0;
+ print_summary = 1;
+ hundred = 1;
+ }
+ } else {
+ /* print summary for all other frames */
+ print_summary = 1;
+ }
+
+ if (print_summary) {
+ char *title;
+ u32 rate;
+
+ if (hundred)
+ title = "100Frames";
+ else if (fc & IEEE80211_FCTL_RETRY)
+ title = "Retry";
+ else if (ieee80211_is_assoc_response(fc))
+ title = "AscRsp";
+ else if (ieee80211_is_reassoc_response(fc))
+ title = "RasRsp";
+ else if (ieee80211_is_probe_response(fc)) {
+ title = "PrbRsp";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_beacon(fc)) {
+ title = "Beacon";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_atim(fc))
+ title = "ATIM";
+ else if (ieee80211_is_auth(fc))
+ title = "Auth";
+ else if (ieee80211_is_deauth(fc))
+ title = "DeAuth";
+ else if (ieee80211_is_disassoc(fc))
+ title = "DisAssoc";
+ else
+ title = "Frame";
+
+ rate = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
+ if (rate == -1)
+ rate = 0;
+ else
+ rate = iwl3945_rates[rate].ieee / 2;
+
+ /* print frame summary.
+ * MAC addresses show just the last byte (for brevity),
+ * but you can hack it to show more, if you'd like to. */
+ if (dataframe)
+ IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+ "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+ title, fc, header->addr1[5],
+ length, rssi, channel, rate);
+ else {
+ /* src/dst addresses assume managed mode */
+ IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+ "src=0x%02x, rssi=%u, tim=%lu usec, "
+ "phy=0x%02x, chnl=%d\n",
+ title, fc, header->addr1[5],
+ header->addr3[5], rssi,
+ tsf_low - priv->scan_start_tsf,
+ phy_flags, channel);
+ }
+ }
+ if (print_dump)
+ iwl3945_print_hex_dump(IWL_DL_RX, data, length);
+}
+#else
+static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
+ struct iwl3945_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100)
+{
+}
+#endif
+
+
static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
struct sk_buff *skb,
struct iwl3945_rx_frame_hdr *rx_hdr,
* the information provided in the skb from the hardware */
s8 signal = stats->ssi;
s8 noise = 0;
- int rate = stats->rate;
+ int rate = stats->rate_idx;
u64 tsf = stats->mactime;
__le16 phy_flags_hw = rx_hdr->phy_flags;
IEEE80211_CHAN_2GHZ),
&iwl3945_rt->rt_chbitmask);
- rate = iwl3945_rate_index_from_plcp(rate);
if (rate == -1)
iwl3945_rt->rt_rate = 0;
else
static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
struct iwl3945_rx_mem_buffer *rxb)
{
+ struct ieee80211_hdr *header;
+ struct ieee80211_rx_status rx_status;
struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
- struct ieee80211_hdr *header;
+ int snr;
u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
- struct ieee80211_rx_status stats = {
- .mactime = le64_to_cpu(rx_end->timestamp),
- .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)),
- .channel = le16_to_cpu(rx_hdr->channel),
- .phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
- MODE_IEEE80211G : MODE_IEEE80211A,
- .antenna = 0,
- .rate = rx_hdr->rate,
- .flag = 0,
- };
u8 network_packet;
- int snr;
+
+ rx_status.antenna = 0;
+ rx_status.flag = 0;
+ rx_status.mactime = le64_to_cpu(rx_end->timestamp);
+ rx_status.freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel));
+ rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+
+ rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
+
+ if (rx_status.band == IEEE80211_BAND_5GHZ)
+ rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
if ((unlikely(rx_stats->phy_count > 20))) {
IWL_DEBUG_DROP
}
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
- iwl3945_handle_data_packet(priv, 1, rxb, &stats);
+ iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
return;
}
/* Convert 3945's rssi indicator to dBm */
- stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
+ rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
/* Set default noise value to -127 */
if (priv->last_rx_noise == 0)
* signal-to-noise ratio (SNR) is (sig_avg / noise_diff).
* Convert linear SNR to dB SNR, then subtract that from rssi dBm
* to obtain noise level in dBm.
- * Calculate stats.signal (quality indicator in %) based on SNR. */
+ * Calculate rx_status.signal (quality indicator in %) based on SNR. */
if (rx_stats_noise_diff) {
snr = rx_stats_sig_avg / rx_stats_noise_diff;
- stats.noise = stats.ssi - iwl3945_calc_db_from_ratio(snr);
- stats.signal = iwl3945_calc_sig_qual(stats.ssi, stats.noise);
+ rx_status.noise = rx_status.ssi -
+ iwl3945_calc_db_from_ratio(snr);
+ rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi,
+ rx_status.noise);
/* If noise info not available, calculate signal quality indicator (%)
* using just the dBm signal level. */
} else {
- stats.noise = priv->last_rx_noise;
- stats.signal = iwl3945_calc_sig_qual(stats.ssi, 0);
+ rx_status.noise = priv->last_rx_noise;
+ rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0);
}
IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
- stats.ssi, stats.noise, stats.signal,
+ rx_status.ssi, rx_status.noise, rx_status.signal,
rx_stats_sig_avg, rx_stats_noise_diff);
- stats.freq = ieee80211chan2mhz(stats.channel);
-
- /* can be covered by iwl3945_report_frame() in most cases */
-/* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */
-
header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
network_packet = iwl3945_is_network_packet(priv, header);
-#ifdef CONFIG_IWL3945_DEBUG
- if (iwl3945_debug_level & IWL_DL_STATS && net_ratelimit())
- IWL_DEBUG_STATS
- ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n",
- network_packet ? '*' : ' ',
- stats.channel, stats.ssi, stats.ssi,
- stats.ssi, stats.rate);
+ IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
+ network_packet ? '*' : ' ',
+ le16_to_cpu(rx_hdr->channel),
+ rx_status.ssi, rx_status.ssi,
+ rx_status.ssi, rx_status.rate_idx);
+#ifdef CONFIG_IWL3945_DEBUG
if (iwl3945_debug_level & (IWL_DL_RX))
/* Set "1" to report good data frames in groups of 100 */
- iwl3945_report_frame(priv, pkt, header, 1);
+ iwl3945_dbg_report_frame(priv, pkt, header, 1);
#endif
if (network_packet) {
priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
priv->last_tsf = le64_to_cpu(rx_end->timestamp);
- priv->last_rx_rssi = stats.ssi;
- priv->last_rx_noise = stats.noise;
+ priv->last_rx_rssi = rx_status.ssi;
+ priv->last_rx_noise = rx_status.noise;
}
switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
}
}
- iwl3945_handle_data_packet(priv, 0, rxb, &stats);
+ iwl3945_handle_data_packet(priv, 0, rxb, &rx_status);
break;
case IEEE80211_FTYPE_CTL:
print_mac(mac2, header->addr2),
print_mac(mac3, header->addr3));
else
- iwl3945_handle_data_packet(priv, 1, rxb, &stats);
+ iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
break;
}
}
struct ieee80211_hdr *hdr, int sta_id, int tx_id)
{
unsigned long flags;
- u16 rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+ u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1);
u16 rate_mask;
int rate;
u8 rts_retry_limit;
priv->stations[sta_id].current_rate.rate_n_flags = rate;
if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
- (sta_id != IWL3945_BROADCAST_ID) &&
+ (sta_id != priv->hw_setting.bcast_sta_id) &&
(sta_id != IWL_MULTICAST_ID))
priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
IWL_DEBUG_INFO("RTP type \n");
else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
- IWL_DEBUG_INFO("ALM-MB type\n");
+ IWL_DEBUG_INFO("3945 RADIO-MB type\n");
iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB);
+ CSR39_HW_IF_CONFIG_REG_BIT_3945_MB);
} else {
- IWL_DEBUG_INFO("ALM-MM type\n");
+ IWL_DEBUG_INFO("3945 RADIO-MM type\n");
iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM);
+ CSR39_HW_IF_CONFIG_REG_BIT_3945_MM);
}
if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) {
IWL_DEBUG_INFO("SKU OP mode is mrc\n");
iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC);
+ CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC);
} else
IWL_DEBUG_INFO("SKU OP mode is basic\n");
IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
priv->eeprom.board_revision);
iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+ CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
} else {
IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
priv->eeprom.board_revision);
iwl3945_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+ CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
}
if (priv->eeprom.almgor_m_version <= 1) {
iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
+ CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
IWL_DEBUG_INFO("Card M type A version is 0x%X\n",
priv->eeprom.almgor_m_version);
} else {
IWL_DEBUG_INFO("Card M type B version is 0x%X\n",
priv->eeprom.almgor_m_version);
iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
+ CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
}
spin_unlock_irqrestore(&priv->lock, flags);
.channel = priv->active_rxon.channel,
};
- txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1;
+ txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1;
ch_info = iwl3945_get_channel_info(priv,
- priv->phymode,
+ priv->band,
le16_to_cpu(priv->active_rxon.channel));
if (!ch_info) {
IWL_ERROR
("Failed to get channel info for channel %d [%d]\n",
- le16_to_cpu(priv->active_rxon.channel), priv->phymode);
+ le16_to_cpu(priv->active_rxon.channel), priv->band);
return -EINVAL;
}
table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index;
}
- switch (priv->phymode) {
- case MODE_IEEE80211A:
+ switch (priv->band) {
+ case IEEE80211_BAND_5GHZ:
IWL_DEBUG_RATE("Select A mode rate scale\n");
/* If one of the following CCK rates is used,
* have it fall back to the 6M OFDM rate */
iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
break;
- case MODE_IEEE80211B:
- IWL_DEBUG_RATE("Select B mode rate scale\n");
+ case IEEE80211_BAND_2GHZ:
+ IWL_DEBUG_RATE("Select B/G mode rate scale\n");
/* If an OFDM rate is used, have it fall back to the
* 1M CCK rates */
for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++)
break;
default:
- IWL_DEBUG_RATE("Select G mode rate scale\n");
+ WARN_ON(1);
break;
}
return -ENOMEM;
}
- priv->hw_setting.ac_queue_count = AC_NUM;
priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE;
priv->hw_setting.max_pkt_size = 2342;
priv->hw_setting.tx_cmd_len = sizeof(struct iwl3945_tx_cmd);
priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
priv->hw_setting.max_stations = IWL3945_STATION_COUNT;
priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID;
+
+ priv->hw_setting.tx_ant_num = 2;
return 0;
}
tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u;
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
- tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID;
+ tx_beacon_cmd->tx.sta_id = priv->hw_setting.bcast_sta_id;
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
frame_size = iwl3945_fill_beacon_frame(priv,
void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv)
{
+ priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx;
priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx;
}
cancel_delayed_work(&priv->thermal_periodic);
}
+static struct iwl_3945_cfg iwl3945_bg_cfg = {
+ .name = "3945BG",
+ .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode",
+ .sku = IWL_SKU_G,
+};
+
+static struct iwl_3945_cfg iwl3945_abg_cfg = {
+ .name = "3945ABG",
+ .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode",
+ .sku = IWL_SKU_A|IWL_SKU_G,
+};
+
struct pci_device_id iwl3945_hw_card_ids[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4222)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4227)},
+ {IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)},
+ {IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)},
+ {IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)},
+ {IWL_PCI_DEVICE(0x4227, 0x1014, iwl3945_bg_cfg)},
+ {IWL_PCI_DEVICE(0x4222, PCI_ANY_ID, iwl3945_abg_cfg)},
+ {IWL_PCI_DEVICE(0x4227, PCI_ANY_ID, iwl3945_abg_cfg)},
{0}
};
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
extern struct pci_device_id iwl3945_hw_card_ids[];
#define DRV_NAME "iwl3945"
-#include "iwl-3945-hw.h"
+#include "iwl-csr.h"
#include "iwl-prph.h"
+#include "iwl-3945-hw.h"
#include "iwl-3945-debug.h"
+/* Change firmware file name, using "-" and incrementing number,
+ * *only* when uCode interface or architecture changes so that it
+ * is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL3945_UCODE_API "-1"
+
/* Default noise level to report when noise measurement is not available.
* This may be because we're:
* 1) Not associated (4965, no beacon statistics being sent to driver)
* space less than this */
} __attribute__ ((packed));
+int iwl3945_queue_space(const struct iwl3945_queue *q);
+int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i);
+
#define MAX_NUM_OF_TBS (20)
/* One for each TFD */
u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */
u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */
- u8 phymode; /* MODE_IEEE80211{A,B,G} */
+ enum ieee80211_band band;
/* Radio/DSP gain settings for each "normal" data Tx rate.
* These include, in addition to RF and DSP gain, a few fields for
};
};
-#ifdef CONFIG_IWL3945_QOS
-
union iwl3945_qos_capabity {
struct {
u8 edca_count:4; /* bit 0-3 */
union iwl3945_qos_capabity qos_cap;
struct iwl3945_qosparam_cmd def_qos_parm;
};
-#endif /*CONFIG_IWL3945_QOS */
#define STA_PS_STATUS_WAKE 0
#define STA_PS_STATUS_SLEEP 1
/**
* struct iwl3945_driver_hw_info
* @max_txq_num: Max # Tx queues supported
- * @ac_queue_count: # Tx queues for EDCA Access Categories (AC)
* @tx_cmd_len: Size of Tx command (but not including frame itself)
+ * @tx_ant_num: Number of TX antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
* @rx_buf_size:
* @max_pkt_size:
*/
struct iwl3945_driver_hw_info {
u16 max_txq_num;
- u16 ac_queue_count;
u16 tx_cmd_len;
+ u16 tx_ant_num;
u16 max_rxq_size;
u32 rx_buf_size;
u32 max_pkt_size;
struct ieee80211_hdr *header);
extern int iwl3945_power_init_handle(struct iwl3945_priv *priv);
extern int iwl3945_eeprom_init(struct iwl3945_priv *priv);
-#ifdef CONFIG_IWL3945_DEBUG
-extern void iwl3945_report_frame(struct iwl3945_priv *priv,
- struct iwl3945_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100);
-#else
-static inline void iwl3945_report_frame(struct iwl3945_priv *priv,
- struct iwl3945_rx_packet *pkt,
- struct ieee80211_hdr *header,
- int group100) {}
-#endif
extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv,
struct iwl3945_rx_mem_buffer *rxb,
void *data, short len,
struct ieee80211_hw *hw;
struct ieee80211_channel *ieee_channels;
struct ieee80211_rate *ieee_rates;
+ struct iwl_3945_cfg *cfg; /* device configuration */
/* temporary frame storage list */
struct list_head free_frames;
int frames_count;
- u8 phymode;
+ enum ieee80211_band band;
int alloc_rxb_skb;
bool add_radiotap;
void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv,
struct iwl3945_rx_mem_buffer *rxb);
- const struct ieee80211_hw_mode *modes;
+ struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
/* spectrum measurement report caching */
struct iwl3945_tx_queue txq[IWL_MAX_NUM_QUEUES];
unsigned long status;
- u32 config;
int last_rx_rssi; /* From Rx packet statisitics */
int last_rx_noise; /* From beacon statistics */
int is_open;
u8 mac80211_registered;
- int is_abg;
u32 notif_missed_beacons;
u16 assoc_capability;
u8 ps_mode;
-#ifdef CONFIG_IWL3945_QOS
struct iwl3945_qos_info qos_data;
-#endif /*CONFIG_IWL3945_QOS */
struct workqueue_struct *workqueue;
static inline u8 is_channel_a_band(const struct iwl3945_channel_info *ch_info)
{
- return ch_info->phymode == MODE_IEEE80211A;
+ return ch_info->band == IEEE80211_BAND_5GHZ;
}
static inline u8 is_channel_bg_band(const struct iwl3945_channel_info *ch_info)
{
- return ((ch_info->phymode == MODE_IEEE80211B) ||
- (ch_info->phymode == MODE_IEEE80211G));
+ return ch_info->band == IEEE80211_BAND_2GHZ;
}
static inline int is_channel_passive(const struct iwl3945_channel_info *ch)
return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
}
-static inline int iwl3945_rate_index_from_plcp(int plcp)
-{
- int i;
-
- for (i = 0; i < IWL_RATE_COUNT; i++)
- if (iwl3945_rates[i].plcp == plcp)
- return i;
- return -1;
-}
-
extern const struct iwl3945_channel_info *iwl3945_get_channel_info(
- const struct iwl3945_priv *priv, int phymode, u16 channel);
+ const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel);
/* Requires full declaration of iwl3945_priv before including */
#include "iwl-3945-io.h"
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#define STA_CONTROL_MODIFY_MSK 0x01
/* key flags __le16*/
-#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7)
-#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0)
-#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1)
-#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2)
-#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3)
+#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007)
+#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000)
+#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001)
+#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002)
+#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003)
#define STA_KEY_FLG_KEYID_POS 8
#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800)
+/* wep key is either from global key (0) or from station info array (1) */
+#define STA_KEY_FLG_MAP_KEY_MSK __constant_cpu_to_le16(0x0008)
+
+/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
+#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000)
+#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000)
/* Flags indicate whether to modify vs. don't change various station params */
#define STA_MODIFY_KEY_MASK 0x01
u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */
u8 reserved1;
__le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
- __le16 reserved2;
+ u8 key_offset;
+ u8 reserved2;
u8 key[16]; /* 16-byte unicast decryption key */
} __attribute__ ((packed));
u8 payload[0];
} __attribute__ ((packed));
-#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1)
+#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1)
-#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0)
+#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0)
-#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
-#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
-#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8)
-#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8)
-#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8)
+#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
+#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
+#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8)
+#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8)
+#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8)
-#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
-#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11)
-#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11)
-#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11)
-#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11)
+#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
+#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11)
+#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11)
+#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11)
+#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11)
struct iwl4965_rx_frame_end {
__le32 status;
__le32 status; /* TX status (for aggregation status of 1st frame) */
} __attribute__ ((packed));
+struct agg_tx_status {
+ __le16 status;
+ __le16 sequence;
+} __attribute__ ((packed));
+
+struct iwl4965_tx_resp_agg {
+ u8 frame_count; /* 1 no aggregation, >1 aggregation */
+ u8 reserved1;
+ u8 failure_rts;
+ u8 failure_frame;
+ __le32 rate_n_flags;
+ __le16 wireless_media_time;
+ __le16 reserved3;
+ __le32 pa_power1;
+ __le32 pa_power2;
+ struct agg_tx_status status; /* TX status (for aggregation status */
+ /* of 1st frame) */
+} __attribute__ ((packed));
+
/*
* REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
*
/* Index of recipient (BA-sending) station in uCode's station table */
u8 sta_id;
u8 tid;
- __le16 ba_seq_ctl;
- __le32 ba_bitmap0;
- __le32 ba_bitmap1;
+ __le16 seq_ctl;
+ __le64 bitmap;
__le16 scd_flow;
__le16 scd_ssn;
} __attribute__ ((packed));
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
do { if ((iwl4965_debug_level & (level)) && net_ratelimit()) \
printk(KERN_ERR DRV_NAME": %c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+static inline void iwl4965_print_hex_dump(int level, void *p, u32 len)
+{
+ if (!(iwl4965_debug_level & level))
+ return;
+
+ print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+ p, len, 1);
+}
#else
+
static inline void IWL_DEBUG(int level, const char *fmt, ...)
{
}
static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
{
}
+static inline void iwl4965_print_hex_dump(int level, void *p, u32 len)
+{
+}
#endif /* CONFIG_IWL4965_DEBUG */
+
+
/*
* To use the debug system;
*
IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a)
#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
+#define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a)
#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
#define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a)
#define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a)
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
/* RSSI to dBm */
#define IWL_RSSI_OFFSET 44
-/*
- * EEPROM related constants, enums, and structures.
- */
-
-/*
- * EEPROM access time values:
- *
- * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG,
- * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit
- * CSR_EEPROM_REG_BIT_CMD (0x2).
- * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
- * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
- * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
- */
-#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
-#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */
-
-/*
- * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags.
- *
- * IBSS and/or AP operation is allowed *only* on those channels with
- * (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because
- * RADAR detection is not supported by the 4965 driver, but is a
- * requirement for establishing a new network for legal operation on channels
- * requiring RADAR detection or restricting ACTIVE scanning.
- *
- * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels.
- * It only indicates that 20 MHz channel use is supported; FAT channel
- * usage is indicated by a separate set of regulatory flags for each
- * FAT channel pair.
- *
- * NOTE: Using a channel inappropriately will result in a uCode error!
- */
-enum {
- EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */
- EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */
- /* Bit 2 Reserved */
- EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */
- EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */
- EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */
- EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */
- EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */
-};
-
-/* SKU Capabilities */
-#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0)
-#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
-
-/* *regulatory* channel data format in eeprom, one for each channel.
- * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */
-struct iwl4965_eeprom_channel {
- u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */
- s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
-} __attribute__ ((packed));
-
-/* 4965 has two radio transmitters (and 3 radio receivers) */
-#define EEPROM_TX_POWER_TX_CHAINS (2)
-
-/* 4965 has room for up to 8 sets of txpower calibration data */
-#define EEPROM_TX_POWER_BANDS (8)
-
-/* 4965 factory calibration measures txpower gain settings for
- * each of 3 target output levels */
-#define EEPROM_TX_POWER_MEASUREMENTS (3)
-
-/* 4965 driver does not work with txpower calibration version < 5.
- * Look for this in calib_version member of struct iwl4965_eeprom. */
-#define EEPROM_TX_POWER_VERSION_NEW (5)
-
-
-/*
- * 4965 factory calibration data for one txpower level, on one channel,
- * measured on one of the 2 tx chains (radio transmitter and associated
- * antenna). EEPROM contains:
- *
- * 1) Temperature (degrees Celsius) of device when measurement was made.
- *
- * 2) Gain table index used to achieve the target measurement power.
- * This refers to the "well-known" gain tables (see iwl-4965-hw.h).
- *
- * 3) Actual measured output power, in half-dBm ("34" = 17 dBm).
- *
- * 4) RF power amplifier detector level measurement (not used).
- */
-struct iwl4965_eeprom_calib_measure {
- u8 temperature; /* Device temperature (Celsius) */
- u8 gain_idx; /* Index into gain table */
- u8 actual_pow; /* Measured RF output power, half-dBm */
- s8 pa_det; /* Power amp detector level (not used) */
-} __attribute__ ((packed));
-
-
-/*
- * 4965 measurement set for one channel. EEPROM contains:
- *
- * 1) Channel number measured
- *
- * 2) Measurements for each of 3 power levels for each of 2 radio transmitters
- * (a.k.a. "tx chains") (6 measurements altogether)
- */
-struct iwl4965_eeprom_calib_ch_info {
- u8 ch_num;
- struct iwl4965_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS]
- [EEPROM_TX_POWER_MEASUREMENTS];
-} __attribute__ ((packed));
-
-/*
- * 4965 txpower subband info.
- *
- * For each frequency subband, EEPROM contains the following:
- *
- * 1) First and last channels within range of the subband. "0" values
- * indicate that this sample set is not being used.
- *
- * 2) Sample measurement sets for 2 channels close to the range endpoints.
- */
-struct iwl4965_eeprom_calib_subband_info {
- u8 ch_from; /* channel number of lowest channel in subband */
- u8 ch_to; /* channel number of highest channel in subband */
- struct iwl4965_eeprom_calib_ch_info ch1;
- struct iwl4965_eeprom_calib_ch_info ch2;
-} __attribute__ ((packed));
-
-
-/*
- * 4965 txpower calibration info. EEPROM contains:
- *
- * 1) Factory-measured saturation power levels (maximum levels at which
- * tx power amplifier can output a signal without too much distortion).
- * There is one level for 2.4 GHz band and one for 5 GHz band. These
- * values apply to all channels within each of the bands.
- *
- * 2) Factory-measured power supply voltage level. This is assumed to be
- * constant (i.e. same value applies to all channels/bands) while the
- * factory measurements are being made.
- *
- * 3) Up to 8 sets of factory-measured txpower calibration values.
- * These are for different frequency ranges, since txpower gain
- * characteristics of the analog radio circuitry vary with frequency.
- *
- * Not all sets need to be filled with data;
- * struct iwl4965_eeprom_calib_subband_info contains range of channels
- * (0 if unused) for each set of data.
- */
-struct iwl4965_eeprom_calib_info {
- u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */
- u8 saturation_power52; /* half-dBm */
- s16 voltage; /* signed */
- struct iwl4965_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS];
-} __attribute__ ((packed));
-
-
-/*
- * 4965 EEPROM map
- */
-struct iwl4965_eeprom {
- u8 reserved0[16];
-#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */
- u16 device_id; /* abs.ofs: 16 */
- u8 reserved1[2];
-#define EEPROM_PMC (2*0x0A) /* 2 bytes */
- u16 pmc; /* abs.ofs: 20 */
- u8 reserved2[20];
-#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */
- u8 mac_address[6]; /* abs.ofs: 42 */
- u8 reserved3[58];
-#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */
- u16 board_revision; /* abs.ofs: 106 */
- u8 reserved4[11];
-#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
- u8 board_pba_number[9]; /* abs.ofs: 119 */
- u8 reserved5[8];
-#define EEPROM_VERSION (2*0x44) /* 2 bytes */
- u16 version; /* abs.ofs: 136 */
-#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */
- u8 sku_cap; /* abs.ofs: 138 */
-#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */
- u8 leds_mode; /* abs.ofs: 139 */
-#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
- u16 oem_mode;
-#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
- u16 wowlan_mode; /* abs.ofs: 142 */
-#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */
- u16 leds_time_interval; /* abs.ofs: 144 */
-#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */
- u8 leds_off_time; /* abs.ofs: 146 */
-#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */
- u8 leds_on_time; /* abs.ofs: 147 */
-#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */
- u8 almgor_m_version; /* abs.ofs: 148 */
-#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */
- u8 antenna_switch_type; /* abs.ofs: 149 */
- u8 reserved6[8];
-#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */
- u16 board_revision_4965; /* abs.ofs: 158 */
- u8 reserved7[13];
-#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */
- u8 board_pba_number_4965[9]; /* abs.ofs: 173 */
- u8 reserved8[10];
-#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */
- u8 sku_id[4]; /* abs.ofs: 192 */
-
-/*
- * Per-channel regulatory data.
- *
- * Each channel that *might* be supported by 3945 or 4965 has a fixed location
- * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
- * txpower (MSB).
- *
- * Entries immediately below are for 20 MHz channel width. FAT (40 MHz)
- * channels (only for 4965, not supported by 3945) appear later in the EEPROM.
- *
- * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
- */
-#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */
- u16 band_1_count; /* abs.ofs: 196 */
-#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */
- struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */
-
-/*
- * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
- * 5.0 GHz channels 7, 8, 11, 12, 16
- * (4915-5080MHz) (none of these is ever supported)
- */
-#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */
- u16 band_2_count; /* abs.ofs: 226 */
-#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */
- struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */
-
-/*
- * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
- * (5170-5320MHz)
- */
-#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */
- u16 band_3_count; /* abs.ofs: 254 */
-#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */
- struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */
-
-/*
- * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
- * (5500-5700MHz)
- */
-#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */
- u16 band_4_count; /* abs.ofs: 280 */
-#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */
- struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */
-
-/*
- * 5.7 GHz channels 145, 149, 153, 157, 161, 165
- * (5725-5825MHz)
- */
-#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */
- u16 band_5_count; /* abs.ofs: 304 */
-#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */
- struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */
-
- u8 reserved10[2];
-
-
-/*
- * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
- *
- * The channel listed is the center of the lower 20 MHz half of the channel.
- * The overall center frequency is actually 2 channels (10 MHz) above that,
- * and the upper half of each FAT channel is centered 4 channels (20 MHz) away
- * from the lower half; e.g. the upper half of FAT channel 1 is channel 5,
- * and the overall FAT channel width centers on channel 3.
- *
- * NOTE: The RXON command uses 20 MHz channel numbers to specify the
- * control channel to which to tune. RXON also specifies whether the
- * control channel is the upper or lower half of a FAT channel.
- *
- * NOTE: 4965 does not support FAT channels on 2.4 GHz.
- */
-#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */
- struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */
- u8 reserved11[2];
-
-/*
- * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64),
- * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
- */
-#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */
- struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */
- u8 reserved12[6];
-
-/*
- * 4965 driver requires txpower calibration format version 5 or greater.
- * Driver does not work with txpower calibration version < 5.
- * This value is simply a 16-bit number, no major/minor versions here.
- */
-#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */
- u16 calib_version; /* abs.ofs: 364 */
- u8 reserved13[2];
- u8 reserved14[96]; /* abs.ofs: 368 */
-
-/*
- * 4965 Txpower calibration data.
- */
-#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */
- struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */
-
- u8 reserved16[140]; /* fill out to full 1024 byte block */
-
-
-} __attribute__ ((packed));
-
-#define IWL_EEPROM_IMAGE_SIZE 1024
-
-/* End of EEPROM */
#include "iwl-4965-commands.h"
#define PCI_REG_WUM8 0x0E8
#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
-/*=== CSR (control and status registers) ===*/
-#define CSR_BASE (0x000)
-
-#define CSR_SW_VER (CSR_BASE+0x000)
-#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
-#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
-#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */
-#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */
-#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/
-#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */
-#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
-#define CSR_GP_CNTRL (CSR_BASE+0x024)
-
-/*
- * Hardware revision info
- * Bit fields:
- * 31-8: Reserved
- * 7-4: Type of device: 0x0 = 4965, 0xd = 3945
- * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D
- * 1-0: "Dash" value, as in A-1, etc.
- *
- * NOTE: Revision step affects calculation of CCK txpower for 4965.
- */
-#define CSR_HW_REV (CSR_BASE+0x028)
-
-/* EEPROM reads */
-#define CSR_EEPROM_REG (CSR_BASE+0x02c)
-#define CSR_EEPROM_GP (CSR_BASE+0x030)
-#define CSR_GP_UCODE (CSR_BASE+0x044)
-#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
-#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
-#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
-#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
-#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
-
-/*
- * Indicates hardware rev, to determine CCK backoff for txpower calculation.
- * Bit fields:
- * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
- */
-#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
-
-/* Hardware interface configuration bits */
-#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010)
-#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00)
-#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
-#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200)
-#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
-
-/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
- * acknowledged (reset) by host writing "1" to flagged bits. */
-#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */
-#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */
-#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */
-#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */
-#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */
-#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */
-#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */
-#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */
-#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */
-#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */
-#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */
-
-#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \
- CSR_INT_BIT_HW_ERR | \
- CSR_INT_BIT_FH_TX | \
- CSR_INT_BIT_SW_ERR | \
- CSR_INT_BIT_RF_KILL | \
- CSR_INT_BIT_SW_RX | \
- CSR_INT_BIT_WAKEUP | \
- CSR_INT_BIT_ALIVE)
-
-/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
-#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */
-#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */
-#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */
-#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */
-#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */
-#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */
-
-#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
- CSR_FH_INT_BIT_RX_CHNL1 | \
- CSR_FH_INT_BIT_RX_CHNL0)
-
-#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \
- CSR_FH_INT_BIT_TX_CHNL0)
-
-
-/* RESET */
-#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001)
-#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002)
-#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
-#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
-#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
-
-/* GP (general purpose) CONTROL */
-#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
-#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
-#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
-#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010)
-
-#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001)
-
-#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000)
-#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000)
-#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000)
-
-
-/* EEPROM REG */
-#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
-#define CSR_EEPROM_REG_BIT_CMD (0x00000002)
-
-/* EEPROM GP */
-#define CSR_EEPROM_GP_VALID_MSK (0x00000006)
-#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
-#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
-
-/* UCODE DRV GP */
-#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
-#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
-#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
-#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
-
-/* GPIO */
-#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200)
-#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000)
-#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER
-
-/* GI Chicken Bits */
-#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
-#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
-
-/*=== HBUS (Host-side Bus) ===*/
-#define HBUS_BASE (0x400)
-
-/*
- * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
- * structures, error log, event log, verifying uCode load).
- * First write to address register, then read from or write to data register
- * to complete the job. Once the address register is set up, accesses to
- * data registers auto-increment the address by one dword.
- * Bit usage for address registers (read or write):
- * 0-31: memory address within device
- */
-#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c)
-#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010)
-#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
-#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)
-
-/*
- * Registers for accessing device's internal peripheral registers
- * (e.g. SCD, BSM, etc.). First write to address register,
- * then read from or write to data register to complete the job.
- * Bit usage for address registers (read or write):
- * 0-15: register address (offset) within device
- * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword)
- */
-#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044)
-#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048)
-#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c)
-#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
-
-/*
- * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
- * Driver sets this to indicate index to next TFD that driver will fill
- * (1 past latest filled).
- * Bit usage:
- * 0-7: queue write index (0-255)
- * 11-8: queue selector (0-15)
- */
-#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
-
-#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
-
-#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
-
#define TFD_QUEUE_SIZE_MAX (256)
#define IWL_NUM_SCAN_RATES (2)
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
*
*/
-#define _iwl4965_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#define _iwl4965_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs))
#ifdef CONFIG_IWL4965_DEBUG
-static inline void __iwl4965_write32(const char *f, u32 l, struct iwl4965_priv *iwl,
+static inline void __iwl4965_write32(const char *f, u32 l, struct iwl4965_priv *priv,
u32 ofs, u32 val)
{
IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
- _iwl4965_write32(iwl, ofs, val);
+ _iwl4965_write32(priv, ofs, val);
}
-#define iwl4965_write32(iwl, ofs, val) \
- __iwl4965_write32(__FILE__, __LINE__, iwl, ofs, val)
+#define iwl4965_write32(priv, ofs, val) \
+ __iwl4965_write32(__FILE__, __LINE__, priv, ofs, val)
#else
-#define iwl4965_write32(iwl, ofs, val) _iwl4965_write32(iwl, ofs, val)
+#define iwl4965_write32(priv, ofs, val) _iwl4965_write32(priv, ofs, val)
#endif
-#define _iwl4965_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#define _iwl4965_read32(priv, ofs) readl((priv)->hw_base + (ofs))
#ifdef CONFIG_IWL4965_DEBUG
-static inline u32 __iwl4965_read32(char *f, u32 l, struct iwl4965_priv *iwl, u32 ofs)
+static inline u32 __iwl4965_read32(char *f, u32 l, struct iwl4965_priv *priv, u32 ofs)
{
IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
- return _iwl4965_read32(iwl, ofs);
+ return _iwl4965_read32(priv, ofs);
}
-#define iwl4965_read32(iwl, ofs) __iwl4965_read32(__FILE__, __LINE__, iwl, ofs)
+#define iwl4965_read32(priv, ofs) __iwl4965_read32(__FILE__, __LINE__, priv, ofs)
#else
#define iwl4965_read32(p, o) _iwl4965_read32(p, o)
#endif
u32 bits, u32 mask, int timeout)
{
int ret = _iwl4965_poll_bit(priv, addr, bits, mask, timeout);
- if (unlikely(ret == -ETIMEDOUT))
- IWL_DEBUG_IO
- ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
- addr, bits, mask, f, l);
- else
- IWL_DEBUG_IO
- ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
- addr, bits, mask, ret, f, l);
+ IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
+ addr, bits, mask,
+ unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l);
return ret;
}
-#define iwl4965_poll_bit(iwl, addr, bits, mask, timeout) \
- __iwl4965_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#define iwl4965_poll_bit(priv, addr, bits, mask, timeout) \
+ __iwl4965_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout)
#else
#define iwl4965_poll_bit(p, a, b, m, t) _iwl4965_poll_bit(p, a, b, m, t)
#endif
"- %s %d\n", addr, mask, ret, f, l);
return ret;
}
-#define iwl4965_poll_direct_bit(iwl, addr, mask, timeout) \
- __iwl4965_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#define iwl4965_poll_direct_bit(priv, addr, mask, timeout) \
+ __iwl4965_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout)
#else
#define iwl4965_poll_direct_bit _iwl4965_poll_direct_bit
#endif
/******************************************************************************
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
/**
* struct iwl4965_scale_tbl_info -- tx params and success history for all rates
*
- * There are two of these in struct iwl_rate_scale_priv,
+ * There are two of these in struct iwl4965_lq_sta,
* one for "active", and one for "search".
*/
struct iwl4965_scale_tbl_info {
struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
};
+#ifdef CONFIG_IWL4965_HT
+
+struct iwl4965_traffic_load {
+ unsigned long time_stamp; /* age of the oldest statistics */
+ u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
+ * slice */
+ u32 total; /* total num of packets during the
+ * last TID_MAX_TIME_DIFF */
+ u8 queue_count; /* number of queues that has
+ * been used since the last cleanup */
+ u8 head; /* start of the circular buffer */
+};
+
+#endif /* CONFIG_IWL4965_HT */
+
/**
- * struct iwl_rate_scale_priv -- driver's rate scaling private structure
+ * struct iwl4965_lq_sta -- driver's rate scaling private structure
*
* Pointer to this gets passed back and forth between driver and mac80211.
*/
u8 valid_antenna;
u8 is_green;
u8 is_dup;
- u8 phymode;
+ enum ieee80211_band band;
u8 ibss_sta_added;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
struct iwl4965_link_quality_cmd lq;
struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
+#ifdef CONFIG_IWL4965_HT
+ struct iwl4965_traffic_load load[TID_MAX_LOAD_COUNT];
+ u8 tx_agg_tid_en;
+#endif
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *rs_sta_dbgfs_scale_table_file;
struct dentry *rs_sta_dbgfs_stats_table_file;
+#ifdef CONFIG_IWL4965_HT
+ struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
+#endif
struct iwl4965_rate dbg_fixed;
struct iwl4965_priv *drv;
#endif
window->stamp = 0;
}
+#ifdef CONFIG_IWL4965_HT
+/*
+ * removes the old data from the statistics. All data that is older than
+ * TID_MAX_TIME_DIFF, will be deleted.
+ */
+static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time)
+{
+ /* The oldest age we want to keep */
+ u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
+
+ while (tl->queue_count &&
+ (tl->time_stamp < oldest_time)) {
+ tl->total -= tl->packet_count[tl->head];
+ tl->packet_count[tl->head] = 0;
+ tl->time_stamp += TID_QUEUE_CELL_SPACING;
+ tl->queue_count--;
+ tl->head++;
+ if (tl->head >= TID_QUEUE_MAX_SIZE)
+ tl->head = 0;
+ }
+}
+
+/*
+ * increment traffic load value for tid and also remove
+ * any old values if passed the certain time period
+ */
+static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid)
+{
+ u32 curr_time = jiffies_to_msecs(jiffies);
+ u32 time_diff;
+ s32 index;
+ struct iwl4965_traffic_load *tl = NULL;
+
+ if (tid >= TID_MAX_LOAD_COUNT)
+ return;
+
+ tl = &lq_data->load[tid];
+
+ curr_time -= curr_time % TID_ROUND_VALUE;
+
+ /* Happens only for the first packet. Initialize the data */
+ if (!(tl->queue_count)) {
+ tl->total = 1;
+ tl->time_stamp = curr_time;
+ tl->queue_count = 1;
+ tl->head = 0;
+ tl->packet_count[0] = 1;
+ return;
+ }
+
+ time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+ index = time_diff / TID_QUEUE_CELL_SPACING;
+
+ /* The history is too long: remove data that is older than */
+ /* TID_MAX_TIME_DIFF */
+ if (index >= TID_QUEUE_MAX_SIZE)
+ rs_tl_rm_old_stats(tl, curr_time);
+
+ index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
+ tl->packet_count[index] = tl->packet_count[index] + 1;
+ tl->total = tl->total + 1;
+
+ if ((index + 1) > tl->queue_count)
+ tl->queue_count = index + 1;
+}
+
+/*
+ get the traffic load value for tid
+*/
+static u32 rs_tl_get_load(struct iwl4965_lq_sta *lq_data, u8 tid)
+{
+ u32 curr_time = jiffies_to_msecs(jiffies);
+ u32 time_diff;
+ s32 index;
+ struct iwl4965_traffic_load *tl = NULL;
+
+ if (tid >= TID_MAX_LOAD_COUNT)
+ return 0;
+
+ tl = &(lq_data->load[tid]);
+
+ curr_time -= curr_time % TID_ROUND_VALUE;
+
+ if (!(tl->queue_count))
+ return 0;
+
+ time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+ index = time_diff / TID_QUEUE_CELL_SPACING;
+
+ /* The history is too long: remove data that is older than */
+ /* TID_MAX_TIME_DIFF */
+ if (index >= TID_QUEUE_MAX_SIZE)
+ rs_tl_rm_old_stats(tl, curr_time);
+
+ return tl->total;
+}
+
+static void rs_tl_turn_on_agg_for_tid(struct iwl4965_priv *priv,
+ struct iwl4965_lq_sta *lq_data, u8 tid,
+ struct sta_info *sta)
+{
+ unsigned long state;
+ DECLARE_MAC_BUF(mac);
+
+ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ state = sta->ampdu_mlme.tid_tx[tid].state;
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+ if (state == HT_AGG_STATE_IDLE &&
+ rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
+ IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n",
+ print_mac(mac, sta->addr), tid);
+ ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
+ }
+}
+
+static void rs_tl_turn_on_agg(struct iwl4965_priv *priv, u8 tid,
+ struct iwl4965_lq_sta *lq_data,
+ struct sta_info *sta)
+{
+ if ((tid < TID_MAX_LOAD_COUNT))
+ rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+ else if (tid == IWL_AGG_ALL_TID)
+ for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
+ rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+}
+
+#endif /* CONFIG_IWLWIFI_HT */
+
/**
* rs_collect_tx_data - Update the success/failure sliding window
*
* packets.
*/
static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
- int scale_index, s32 tpt, u32 status)
+ int scale_index, s32 tpt, int retries,
+ int successes)
{
struct iwl4965_rate_scale_data *window = NULL;
u64 mask;
* subtract "1" from the success counter (this is the main reason
* we keep these bitmaps!).
*/
- if (window->counter >= win_size) {
- window->counter = win_size - 1;
- mask = 1;
- mask = (mask << (win_size - 1));
- if ((window->data & mask)) {
- window->data &= ~mask;
- window->success_counter = window->success_counter - 1;
+ while (retries > 0) {
+ if (window->counter >= win_size) {
+ window->counter = win_size - 1;
+ mask = 1;
+ mask = (mask << (win_size - 1));
+ if (window->data & mask) {
+ window->data &= ~mask;
+ window->success_counter =
+ window->success_counter - 1;
+ }
}
- }
- /* Increment frames-attempted counter */
- window->counter = window->counter + 1;
+ /* Increment frames-attempted counter */
+ window->counter++;
+
+ /* Shift bitmap by one frame (throw away oldest history),
+ * OR in "1", and increment "success" if this
+ * frame was successful. */
+ mask = window->data;
+ window->data = (mask << 1);
+ if (successes > 0) {
+ window->success_counter = window->success_counter + 1;
+ window->data |= 0x1;
+ successes--;
+ }
- /* Shift bitmap by one frame (throw away oldest history),
- * OR in "1", and increment "success" if this frame was successful. */
- mask = window->data;
- window->data = (mask << 1);
- if (status != 0) {
- window->success_counter = window->success_counter + 1;
- window->data |= 0x1;
+ retries--;
}
/* Calculate current success ratio, avoid divide-by-0! */
* fill "search" or "active" tx mode table.
*/
static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate,
- int phymode, struct iwl4965_scale_tbl_info *tbl,
+ enum ieee80211_band band,
+ struct iwl4965_scale_tbl_info *tbl,
int *rate_idx)
{
int index;
u32 ant_msk;
- index = iwl4965_rate_index_from_plcp(mcs_rate->rate_n_flags);
+ index = iwl4965_hwrate_to_plcp_idx(mcs_rate->rate_n_flags);
if (index == IWL_RATE_INVALID) {
*rate_idx = -1;
tbl->lq_type = LQ_NONE;
else {
- if (phymode == MODE_IEEE80211A)
+ if (band == IEEE80211_BAND_5GHZ)
tbl->lq_type = LQ_A;
else
tbl->lq_type = LQ_G;
if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
switch_to_legacy = 1;
scale_index = rs_ht_to_legacy[scale_index];
- if (lq_sta->phymode == MODE_IEEE80211A)
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
tbl->lq_type = LQ_A;
else
tbl->lq_type = LQ_G;
/* Mask with station rate restriction */
if (is_legacy(tbl->lq_type)) {
/* supp_rates has no CCK bits in A mode */
- if (lq_sta->phymode == (u8) MODE_IEEE80211A)
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
rate_mask = (u16)(rate_mask &
(lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
else
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = local_to_hw(local);
struct iwl4965_rate_scale_data *window = NULL;
struct iwl4965_rate_scale_data *search_win = NULL;
struct iwl4965_rate tx_mcs;
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
return;
+ /* This packet was aggregated but doesn't carry rate scale info */
+ if ((tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) &&
+ !(tx_resp->flags & IEEE80211_TX_STATUS_AMPDU))
+ return;
+
retries = tx_resp->retry_count;
if (retries > 15)
retries = 15;
+ rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
- if (!sta || !sta->rate_ctrl_priv) {
- if (sta)
- sta_info_put(sta);
- return;
- }
+ if (!sta || !sta->rate_ctrl_priv)
+ goto out;
+
lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
if (!priv->lq_mngr.lq_ready)
- return;
+ goto out;
if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
!lq_sta->ibss_sta_added)
- return;
+ goto out;
table = &lq_sta->lq;
active_index = lq_sta->active_tbl;
search_win = (struct iwl4965_rate_scale_data *)
&(search_tbl->win[0]);
- tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
-
- rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
- &tbl_type, &rs_index);
- if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) {
- IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n",
- rs_index, tx_mcs.rate_n_flags);
- sta_info_put(sta);
- return;
- }
-
/*
* Ignore this Tx frame response if its initial rate doesn't match
* that of latest Link Quality command. There may be stragglers
* to check "search" mode, or a prior "search" mode after we've moved
* to a new "search" mode (which might become the new "active" mode).
*/
- if (retries &&
- (tx_mcs.rate_n_flags !=
- le32_to_cpu(table->rs_table[0].rate_n_flags))) {
- IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n",
- tx_mcs.rate_n_flags,
- le32_to_cpu(table->rs_table[0].rate_n_flags));
- sta_info_put(sta);
- return;
+ tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[0].rate_n_flags);
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index);
+ if (priv->band == IEEE80211_BAND_5GHZ)
+ rs_index -= IWL_FIRST_OFDM_RATE;
+
+ if ((tx_resp->control.tx_rate == NULL) ||
+ (tbl_type.is_SGI ^
+ !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) ||
+ (tbl_type.is_fat ^
+ !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) ||
+ (tbl_type.is_dup ^
+ !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) ||
+ (tbl_type.antenna_type ^
+ tx_resp->control.antenna_sel_tx) ||
+ (!!(tx_mcs.rate_n_flags & RATE_MCS_HT_MSK) ^
+ !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) ||
+ (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^
+ !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) ||
+ (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
+ tx_resp->control.tx_rate->bitrate)) {
+ IWL_DEBUG_RATE("initial rate does not match 0x%x\n",
+ tx_mcs.rate_n_flags);
+ goto out;
}
/* Update frame history window with "failure" for each Tx retry. */
* Each tx attempt steps one entry deeper in the rate table. */
tx_mcs.rate_n_flags =
le32_to_cpu(table->rs_table[index].rate_n_flags);
- rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->band,
&tbl_type, &rs_index);
/* If type matches "search" table,
tpt = search_tbl->expected_tpt[rs_index];
else
tpt = 0;
- rs_collect_tx_data(search_win, rs_index, tpt, 0);
+ rs_collect_tx_data(search_win, rs_index, tpt, 1, 0);
/* Else if type matches "current/active" table,
* add failure to "current/active" history */
tpt = curr_tbl->expected_tpt[rs_index];
else
tpt = 0;
- rs_collect_tx_data(window, rs_index, tpt, 0);
+ rs_collect_tx_data(window, rs_index, tpt, 1, 0);
}
/* If not searching for a new mode, increment failed counter
* if Tx was successful first try, use original rate,
* else look up the rate that was, finally, successful.
*/
- if (!tx_resp->retry_count)
- tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
- else
- tx_mcs.rate_n_flags =
- le32_to_cpu(table->rs_table[index].rate_n_flags);
-
- rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
- &tbl_type, &rs_index);
+ tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags);
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index);
/* Update frame history window with "success" if Tx got ACKed ... */
if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
tpt = search_tbl->expected_tpt[rs_index];
else
tpt = 0;
- rs_collect_tx_data(search_win,
- rs_index, tpt, status);
-
+ if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU)
+ rs_collect_tx_data(search_win, rs_index, tpt,
+ tx_resp->ampdu_ack_len,
+ tx_resp->ampdu_ack_map);
+ else
+ rs_collect_tx_data(search_win, rs_index, tpt,
+ 1, status);
/* Else if type matches "current/active" table,
* add final tx status to "current/active" history */
} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
tpt = curr_tbl->expected_tpt[rs_index];
else
tpt = 0;
- rs_collect_tx_data(window, rs_index, tpt, status);
+ if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU)
+ rs_collect_tx_data(window, rs_index, tpt,
+ tx_resp->ampdu_ack_len,
+ tx_resp->ampdu_ack_map);
+ else
+ rs_collect_tx_data(window, rs_index, tpt,
+ 1, status);
}
/* If not searching for new mode, increment success/failed counter
* ... these help determine when to start searching again */
if (lq_sta->stay_in_tbl) {
- if (status)
- lq_sta->total_success++;
- else
- lq_sta->total_failed++;
+ if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) {
+ lq_sta->total_success += tx_resp->ampdu_ack_map;
+ lq_sta->total_failed +=
+ (tx_resp->ampdu_ack_len - tx_resp->ampdu_ack_map);
+ } else {
+ if (status)
+ lq_sta->total_success++;
+ else
+ lq_sta->total_failed++;
+ }
}
/* See if there's a better rate or modulation mode to try. */
rs_rate_scale_perform(priv, dev, hdr, sta);
- sta_info_put(sta);
+out:
+ rcu_read_unlock();
return;
}
return 0;
#else
return -1;
-#endif /*CONFIG_IWL4965_HT */
+#endif /*CONFIG_IWL4965_HT */
}
/*
#else
return -1;
-#endif /*CONFIG_IWL4965_HT */
+#endif /*CONFIG_IWL4965_HT */
}
/*
break;
case IWL_SISO_SWITCH_GI:
IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
+
memcpy(search_tbl, tbl, sz);
search_tbl->action = 0;
if (search_tbl->is_SGI)
case IWL_MIMO_SWITCH_ANTENNA_B:
IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
+
/* Set up new search table for SISO */
memcpy(search_tbl, tbl, sz);
search_tbl->lq_type = LQ_SISO;
u8 active_tbl = 0;
u8 done_search = 0;
u16 high_low;
+#ifdef CONFIG_IWL4965_HT
+ u8 tid = MAX_TID_COUNT;
+ __le16 *qc;
+#endif
IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
}
lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
+#ifdef CONFIG_IWL4965_HT
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ rs_tl_add_packet(lq_sta, tid);
+ }
+#endif
/*
* Select rate-scale / modulation-mode table to work with in
* the rest of this function: "search" if searching for better
is_green = lq_sta->is_green;
/* current tx rate */
- index = sta->last_txrate;
+ index = sta->last_txrate_idx;
IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
tbl->lq_type);
/* mask with station rate restriction */
if (is_legacy(tbl->lq_type)) {
- if (lq_sta->phymode == (u8) MODE_IEEE80211A)
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
/* supp_rates has no CCK bits in A mode */
rate_scale_index_msk = (u16) (rate_mask &
(lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
tbl = &(lq_sta->lq_info[active_tbl]);
/* Revert to "active" rate and throughput info */
- index = iwl4965_rate_index_from_plcp(
+ index = iwl4965_hwrate_to_plcp_idx(
tbl->current_rate.rate_n_flags);
current_tpt = lq_sta->last_tpt;
rs_rate_scale_clear_window(&(tbl->win[i]));
/* Use new "search" start rate */
- index = iwl4965_rate_index_from_plcp(
+ index = iwl4965_hwrate_to_plcp_idx(
tbl->current_rate.rate_n_flags);
IWL_DEBUG_HT("Switch current mcs: %X index: %d\n",
* mode for a while before next round of mode comparisons. */
if (lq_sta->enable_counter &&
(lq_sta->action_counter >= IWL_ACTION_LIMIT)) {
-#ifdef CONFIG_IWL4965_HT_AGG
- /* If appropriate, set up aggregation! */
- if ((lq_sta->last_tpt > TID_AGG_TPT_THREHOLD) &&
- (priv->lq_mngr.agg_ctrl.auto_agg)) {
- priv->lq_mngr.agg_ctrl.tid_retry =
- TID_ALL_SPECIFIED;
- schedule_work(&priv->agg_work);
+#ifdef CONFIG_IWL4965_HT
+ if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
+ (lq_sta->tx_agg_tid_en & (1 << tid)) &&
+ (tid != MAX_TID_COUNT)) {
+ IWL_DEBUG_HT("try to aggregate tid %d\n", tid);
+ rs_tl_turn_on_agg(priv, tid, lq_sta, sta);
}
-#endif /*CONFIG_IWL4965_HT_AGG */
+#endif /*CONFIG_IWL4965_HT */
lq_sta->action_counter = 0;
rs_set_stay_in_table(0, lq_sta);
}
out:
rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);
i = index;
- sta->last_txrate = i;
+ sta->last_txrate_idx = i;
- /* sta->txrate is an index to A mode rates which start
+ /* sta->txrate_idx is an index to A mode rates which start
* at IWL_FIRST_OFDM_RATE
*/
- if (lq_sta->phymode == (u8) MODE_IEEE80211A)
- sta->txrate = i - IWL_FIRST_OFDM_RATE;
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
+ sta->txrate_idx = i - IWL_FIRST_OFDM_RATE;
else
- sta->txrate = i;
+ sta->txrate_idx = i;
return;
}
goto out;
lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
- i = sta->last_txrate;
+ i = sta->last_txrate_idx;
if ((lq_sta->lq.sta_id == 0xff) &&
(priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK;
tbl->antenna_type = ANT_AUX;
- rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx);
+ rs_get_tbl_info_from_mcs(&mcs_rate, priv->band, tbl, &rate_idx);
if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))
rs_toggle_antenna(&mcs_rate, tbl);
}
static void rs_get_rate(void *priv_rate, struct net_device *dev,
- struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+ struct ieee80211_supported_band *sband,
+ struct sk_buff *skb,
struct rate_selection *sel)
{
IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
+ rcu_read_lock();
+
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest
fc = le16_to_cpu(hdr->frame_control);
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) {
- sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
- if (sta)
- sta_info_put(sta);
- return;
+ sel->rate = rate_lowest(local, sband, sta);
+ goto out;
}
lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
- i = sta->last_txrate;
+ i = sta->last_txrate_idx;
if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
!lq_sta->ibss_sta_added) {
goto done;
}
- done:
+done:
if ((i < 0) || (i > IWL_RATE_COUNT)) {
- sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
- return;
+ sel->rate = rate_lowest(local, sband, sta);
+ goto out;
}
- sta_info_put(sta);
sel->rate = &priv->ieee_rates[i];
+out:
+ rcu_read_unlock();
}
static void *rs_alloc_sta(void *priv, gfp_t gfp)
{
int i, j;
struct ieee80211_conf *conf = &local->hw.conf;
- struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+ struct ieee80211_supported_band *sband;
struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
struct iwl4965_lq_sta *lq_sta = priv_sta;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
lq_sta->flush_timer = 0;
- lq_sta->supp_rates = sta->supp_rates;
- sta->txrate = 3;
+ lq_sta->supp_rates = sta->supp_rates[sband->band];
+ sta->txrate_idx = 3;
for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i]));
}
/* Find highest tx rate supported by hardware and destination station */
- for (i = 0; i < mode->num_rates; i++) {
- if ((sta->supp_rates & BIT(i)) &&
- (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
- sta->txrate = i;
- }
- sta->last_txrate = sta->txrate;
+ for (i = 0; i < sband->n_bitrates; i++)
+ if (sta->supp_rates[sband->band] & BIT(i))
+ sta->txrate_idx = i;
+
+ sta->last_txrate_idx = sta->txrate_idx;
+ /* WTF is with this bogus comment? A doesn't have cck rates */
/* For MODE_IEEE80211A, cck rates are at end of rate table */
- if (local->hw.conf.phymode == MODE_IEEE80211A)
- sta->last_txrate += IWL_FIRST_OFDM_RATE;
+ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
+ sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
lq_sta->is_dup = 0;
lq_sta->valid_antenna = priv->valid_antenna;
lq_sta->active_rate = priv->active_rate;
lq_sta->active_rate &= ~(0x1000);
lq_sta->active_rate_basic = priv->active_rate_basic;
- lq_sta->phymode = priv->phymode;
+ lq_sta->band = priv->band;
#ifdef CONFIG_IWL4965_HT
/*
* active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n",
lq_sta->active_siso_rate,
lq_sta->active_mimo_rate);
+ /* as default allow aggregation for all tids */
+ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
#endif /*CONFIG_IWL4965_HT*/
#ifdef CONFIG_MAC80211_DEBUGFS
lq_sta->drv = priv;
rs_dbgfs_set_mcs(lq_sta, tx_mcs, index);
/* Interpret rate_n_flags */
- rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->phymode,
+ rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->band,
&tbl_type, &rate_idx);
/* How many times should we repeat the initial rate? */
index++;
}
- rs_get_tbl_info_from_mcs(&new_rate, lq_sta->phymode, &tbl_type,
+ rs_get_tbl_info_from_mcs(&new_rate, lq_sta->band, &tbl_type,
&rate_idx);
/* Indicate to uCode which entries might be MIMO.
IWL_DEBUG_RATE("enter\n");
priv->lq_mngr.lq_ready = 0;
-#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
- if (priv->lq_mngr.agg_ctrl.granted_ba)
- iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);
-#endif /*CONFIG_IWL4965_HT_AGG */
-#endif /* CONFIG_IWL4965_HT */
IWL_DEBUG_RATE("leave\n");
}
{
u32 base_rate;
- if (lq_sta->phymode == (u8) MODE_IEEE80211A)
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
base_rate = 0x800D;
else
base_rate = 0x820A;
lq_sta->rs_sta_dbgfs_stats_table_file =
debugfs_create_file("rate_stats_table", 0600, dir,
lq_sta, &rs_sta_dbgfs_stats_table_ops);
+#ifdef CONFIG_IWL4965_HT
+ lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
+ debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
+ &lq_sta->tx_agg_tid_en);
+#endif
+
}
static void rs_remove_debugfs(void *priv, void *priv_sta)
struct iwl4965_lq_sta *lq_sta = priv_sta;
debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+#ifdef CONFIG_IWL4965_HT
+ debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
+#endif
}
#endif
u32 max_time = 0;
u8 lq_type, antenna;
+ rcu_read_lock();
+
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
- if (sta) {
- sta_info_put(sta);
+ if (sta)
IWL_DEBUG_RATE("leave - no private rate data!\n");
- } else
+ else
IWL_DEBUG_RATE("leave - no station!\n");
+ rcu_read_unlock();
return sprintf(buf, "station %d not found\n", sta_id);
}
cnt += sprintf(&buf[cnt], "\nrate scale type %d antenna %d "
"active_search %d rate index %d\n", lq_type, antenna,
- lq_sta->search_better_tbl, sta->last_txrate);
+ lq_sta->search_better_tbl, sta->last_txrate_idx);
- sta_info_put(sta);
+ rcu_read_unlock();
return cnt;
}
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
#define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */
+/* load per tid defines for A-MPDU activation */
+#define IWL_AGG_TPT_THREHOLD 0
+#define IWL_AGG_LOAD_THRESHOLD 10
+#define IWL_AGG_ALL_TID 0xff
+#define TID_QUEUE_CELL_SPACING 50 /*mS */
+#define TID_QUEUE_MAX_SIZE 20
+#define TID_ROUND_VALUE 5 /* mS */
+#define TID_MAX_LOAD_COUNT 8
+
+#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
+#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
+
extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
enum iwl4965_table_type {
return rate;
}
-extern int iwl4965_rate_index_from_plcp(int plcp);
+extern int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags);
/**
* iwl4965_fill_rs_info - Fill an output text buffer with the rate representation
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
+#include "iwl-eeprom.h"
+#include "iwl-core.h"
#include "iwl-4965.h"
#include "iwl-helpers.h"
IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
};
+#ifdef CONFIG_IWL4965_HT
+
+static const u16 default_tid_to_tx_fifo[] = {
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC0,
+ IWL_TX_FIFO_AC0,
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_AC3
+};
+
+#endif /*CONFIG_IWL4965_HT */
+
static int is_fat_channel(__le32 rxon_flags)
{
return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
return 0;
}
+int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags)
+{
+ int idx = 0;
+
+ /* 4965 HT rate format */
+ if (rate_n_flags & RATE_MCS_HT_MSK) {
+ idx = (rate_n_flags & 0xff);
+
+ if (idx >= IWL_RATE_MIMO_6M_PLCP)
+ idx = idx - IWL_RATE_MIMO_6M_PLCP;
+
+ idx += IWL_FIRST_OFDM_RATE;
+ /* skip 9M not supported in ht*/
+ if (idx >= IWL_RATE_9M_INDEX)
+ idx += 1;
+ if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
+ return idx;
+
+ /* 4965 legacy rate format, search for match in table */
+ } else {
+ for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++)
+ if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF))
+ return idx;
+ }
+
+ return -1;
+}
+
+/**
+ * translate ucode response to mac80211 tx status control values
+ */
+void iwl4965_hwrate_to_tx_control(struct iwl4965_priv *priv, u32 rate_n_flags,
+ struct ieee80211_tx_control *control)
+{
+ int rate_index;
+
+ control->antenna_sel_tx =
+ ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_A_POS);
+ if (rate_n_flags & RATE_MCS_HT_MSK)
+ control->flags |= IEEE80211_TXCTL_OFDM_HT;
+ if (rate_n_flags & RATE_MCS_GF_MSK)
+ control->flags |= IEEE80211_TXCTL_GREEN_FIELD;
+ if (rate_n_flags & RATE_MCS_FAT_MSK)
+ control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH;
+ if (rate_n_flags & RATE_MCS_DUP_MSK)
+ control->flags |= IEEE80211_TXCTL_DUP_DATA;
+ if (rate_n_flags & RATE_MCS_SGI_MSK)
+ control->flags |= IEEE80211_TXCTL_SHORT_GI;
+ /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use
+ * IEEE80211_BAND_2GHZ band as it contains all the rates */
+ rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags);
+ if (rate_index == -1)
+ control->tx_rate = NULL;
+ else
+ control->tx_rate =
+ &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index];
+}
+
/*
* Determine how many receiver/antenna chains to use.
* More provides better reception via diversity. Fewer saves power.
start = IWL_STA_ID;
if (is_broadcast_ether_addr(addr))
- return IWL4965_BROADCAST_ID;
+ return priv->hw_setting.bcast_sta_id;
spin_lock_irqsave(&priv->sta_lock, flags);
for (i = start; i < priv->hw_setting.max_stations; i++)
*
* Does not set up a command, or touch hardware.
*/
-int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel,
+int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv,
+ enum ieee80211_band band, u16 channel,
const struct iwl4965_eeprom_channel *eeprom_ch,
u8 fat_extension_channel)
{
struct iwl4965_channel_info *ch_info;
ch_info = (struct iwl4965_channel_info *)
- iwl4965_get_channel_info(priv, phymode, channel);
+ iwl4965_get_channel_info(priv, band, channel);
if (!is_channel_valid(ch_info))
return -1;
/* set CSR_HW_CONFIG_REG for uCode use */
- iwl4965_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R |
- CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
- CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+ iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR49_HW_IF_CONFIG_REG_BIT_4965_R |
+ CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI);
rc = iwl4965_grab_nic_access(priv);
if (rc < 0) {
memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl4965_shared));
priv->hw_setting.max_txq_num = iwl4965_param_queues_num;
- priv->hw_setting.ac_queue_count = AC_NUM;
priv->hw_setting.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
priv->hw_setting.max_pkt_size = priv->hw_setting.rx_buf_size - 256;
priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
+
+ priv->hw_setting.tx_ant_num = 2;
+
return 0;
}
}
static const struct iwl4965_channel_info *
-iwl4965_get_channel_txpower_info(struct iwl4965_priv *priv, u8 phymode, u16 channel)
+iwl4965_get_channel_txpower_info(struct iwl4965_priv *priv,
+ enum ieee80211_band band, u16 channel)
{
const struct iwl4965_channel_info *ch_info;
- ch_info = iwl4965_get_channel_info(priv, phymode, channel);
+ ch_info = iwl4965_get_channel_info(priv, band, channel);
if (!is_channel_valid(ch_info))
return NULL;
/* Get current (RXON) channel, band, width */
ch_info =
- iwl4965_get_channel_txpower_info(priv, priv->phymode, channel);
+ iwl4965_get_channel_txpower_info(priv, priv->band, channel);
IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band,
is_fat);
return -EAGAIN;
}
- band = ((priv->phymode == MODE_IEEE80211B) ||
- (priv->phymode == MODE_IEEE80211G));
+ band = priv->band == IEEE80211_BAND_2GHZ;
is_fat = is_fat_channel(priv->active_rxon.flags);
struct iwl4965_channel_switch_cmd cmd = { 0 };
const struct iwl4965_channel_info *ch_info;
- band = ((priv->phymode == MODE_IEEE80211B) ||
- (priv->phymode == MODE_IEEE80211G));
+ band = priv->band == IEEE80211_BAND_2GHZ;
- ch_info = iwl4965_get_channel_info(priv, priv->phymode, channel);
+ ch_info = iwl4965_get_channel_info(priv, priv->band, channel);
is_fat = is_fat_channel(priv->staging_rxon.flags);
u16 fc = le16_to_cpu(hdr->frame_control);
u8 rate_plcp;
u16 rate_flags = 0;
- int rate_idx = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+ int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1);
rate_plcp = iwl4965_rates[rate_idx].plcp;
tx_beacon_cmd = &frame->u.beacon;
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
- tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID;
+ tx_beacon_cmd->tx.sta_id = priv->hw_setting.bcast_sta_id;
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
frame_size = iwl4965_fill_beacon_frame(priv,
IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
}
-#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
-/*
- get the traffic load value for tid
-*/
-static u32 iwl4965_tl_get_load(struct iwl4965_priv *priv, u8 tid)
-{
- u32 load = 0;
- u32 current_time = jiffies_to_msecs(jiffies);
- u32 time_diff;
- s32 index;
- unsigned long flags;
- struct iwl4965_traffic_load *tid_ptr = NULL;
-
- if (tid >= TID_MAX_LOAD_COUNT)
- return 0;
-
- tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
-
- current_time -= current_time % TID_ROUND_VALUE;
-
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- if (!(tid_ptr->queue_count))
- goto out;
-
- time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
- index = time_diff / TID_QUEUE_CELL_SPACING;
-
- if (index >= TID_QUEUE_MAX_SIZE) {
- u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
-
- while (tid_ptr->queue_count &&
- (tid_ptr->time_stamp < oldest_time)) {
- tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
- tid_ptr->packet_count[tid_ptr->head] = 0;
- tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
- tid_ptr->queue_count--;
- tid_ptr->head++;
- if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
- tid_ptr->head = 0;
- }
- }
- load = tid_ptr->total;
-
- out:
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- return load;
-}
-
-/*
- increment traffic load value for tid and also remove
- any old values if passed the certian time period
-*/
-static void iwl4965_tl_add_packet(struct iwl4965_priv *priv, u8 tid)
-{
- u32 current_time = jiffies_to_msecs(jiffies);
- u32 time_diff;
- s32 index;
- unsigned long flags;
- struct iwl4965_traffic_load *tid_ptr = NULL;
-
- if (tid >= TID_MAX_LOAD_COUNT)
- return;
-
- tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
-
- current_time -= current_time % TID_ROUND_VALUE;
-
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- if (!(tid_ptr->queue_count)) {
- tid_ptr->total = 1;
- tid_ptr->time_stamp = current_time;
- tid_ptr->queue_count = 1;
- tid_ptr->head = 0;
- tid_ptr->packet_count[0] = 1;
- goto out;
- }
-
- time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
- index = time_diff / TID_QUEUE_CELL_SPACING;
-
- if (index >= TID_QUEUE_MAX_SIZE) {
- u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
-
- while (tid_ptr->queue_count &&
- (tid_ptr->time_stamp < oldest_time)) {
- tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
- tid_ptr->packet_count[tid_ptr->head] = 0;
- tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
- tid_ptr->queue_count--;
- tid_ptr->head++;
- if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
- tid_ptr->head = 0;
- }
- }
-
- index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE;
- tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1;
- tid_ptr->total = tid_ptr->total + 1;
-
- if ((index + 1) > tid_ptr->queue_count)
- tid_ptr->queue_count = index + 1;
- out:
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
-
-}
-
-#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS 7
-enum HT_STATUS {
- BA_STATUS_FAILURE = 0,
- BA_STATUS_INITIATOR_DELBA,
- BA_STATUS_RECIPIENT_DELBA,
- BA_STATUS_RENEW_ADDBA_REQUEST,
- BA_STATUS_ACTIVE,
-};
-
-/**
- * iwl4964_tl_ba_avail - Find out if an unused aggregation queue is available
- */
-static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv)
-{
- int i;
- struct iwl4965_lq_mngr *lq;
- u8 count = 0;
- u16 msk;
-
- lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
-
- /* Find out how many agg queues are in use */
- for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) {
- msk = 1 << i;
- if ((lq->agg_ctrl.granted_ba & msk) ||
- (lq->agg_ctrl.wait_for_agg_status & msk))
- count++;
- }
-
- if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS)
- return 1;
-
- return 0;
-}
-
-static void iwl4965_ba_status(struct iwl4965_priv *priv,
- u8 tid, enum HT_STATUS status);
-
-static int iwl4965_perform_addba(struct iwl4965_priv *priv, u8 tid, u32 length,
- u32 ba_timeout)
-{
- int rc;
-
- rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid);
- if (rc)
- iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
-
- return rc;
-}
-
-static int iwl4965_perform_delba(struct iwl4965_priv *priv, u8 tid)
-{
- int rc;
-
- rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid);
- if (rc)
- iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
-
- return rc;
-}
-
-static void iwl4965_turn_on_agg_for_tid(struct iwl4965_priv *priv,
- struct iwl4965_lq_mngr *lq,
- u8 auto_agg, u8 tid)
-{
- u32 tid_msk = (1 << tid);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
-/*
- if ((auto_agg) && (!lq->enable_counter)){
- lq->agg_ctrl.next_retry = 0;
- lq->agg_ctrl.tid_retry = 0;
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- return;
- }
-*/
- if (!(lq->agg_ctrl.granted_ba & tid_msk) &&
- (lq->agg_ctrl.requested_ba & tid_msk)) {
- u8 available_queues;
- u32 load;
-
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- available_queues = iwl4964_tl_ba_avail(priv);
- load = iwl4965_tl_get_load(priv, tid);
-
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- if (!available_queues) {
- if (auto_agg)
- lq->agg_ctrl.tid_retry |= tid_msk;
- else {
- lq->agg_ctrl.requested_ba &= ~tid_msk;
- lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
- }
- } else if ((auto_agg) &&
- ((load <= lq->agg_ctrl.tid_traffic_load_threshold) ||
- ((lq->agg_ctrl.wait_for_agg_status & tid_msk))))
- lq->agg_ctrl.tid_retry |= tid_msk;
- else {
- lq->agg_ctrl.wait_for_agg_status |= tid_msk;
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- iwl4965_perform_addba(priv, tid, 0x40,
- lq->agg_ctrl.ba_timeout);
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- }
- }
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
-}
-
-static void iwl4965_turn_on_agg(struct iwl4965_priv *priv, u8 tid)
-{
- struct iwl4965_lq_mngr *lq;
- unsigned long flags;
-
- lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
-
- if ((tid < TID_MAX_LOAD_COUNT))
- iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg,
- tid);
- else if (tid == TID_ALL_SPECIFIED) {
- if (lq->agg_ctrl.requested_ba) {
- for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
- iwl4965_turn_on_agg_for_tid(priv, lq,
- lq->agg_ctrl.auto_agg, tid);
- } else {
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- lq->agg_ctrl.tid_retry = 0;
- lq->agg_ctrl.next_retry = 0;
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- }
- }
-
-}
-
-void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid)
-{
- u32 tid_msk;
- struct iwl4965_lq_mngr *lq;
- unsigned long flags;
-
- lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
-
- if ((tid < TID_MAX_LOAD_COUNT)) {
- tid_msk = 1 << tid;
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- lq->agg_ctrl.wait_for_agg_status |= tid_msk;
- lq->agg_ctrl.requested_ba &= ~tid_msk;
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- iwl4965_perform_delba(priv, tid);
- } else if (tid == TID_ALL_SPECIFIED) {
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
- tid_msk = 1 << tid;
- lq->agg_ctrl.wait_for_agg_status |= tid_msk;
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- iwl4965_perform_delba(priv, tid);
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- }
- lq->agg_ctrl.requested_ba = 0;
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- }
-}
-
-/**
- * iwl4965_ba_status - Update driver's link quality mgr with tid's HT status
- */
-static void iwl4965_ba_status(struct iwl4965_priv *priv,
- u8 tid, enum HT_STATUS status)
-{
- struct iwl4965_lq_mngr *lq;
- u32 tid_msk = (1 << tid);
- unsigned long flags;
-
- lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
-
- if ((tid >= TID_MAX_LOAD_COUNT))
- goto out;
-
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- switch (status) {
- case BA_STATUS_ACTIVE:
- if (!(lq->agg_ctrl.granted_ba & tid_msk))
- lq->agg_ctrl.granted_ba |= tid_msk;
- break;
- default:
- if ((lq->agg_ctrl.granted_ba & tid_msk))
- lq->agg_ctrl.granted_ba &= ~tid_msk;
- break;
- }
-
- lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
- if (status != BA_STATUS_ACTIVE) {
- if (lq->agg_ctrl.auto_agg) {
- lq->agg_ctrl.tid_retry |= tid_msk;
- lq->agg_ctrl.next_retry =
- jiffies + msecs_to_jiffies(500);
- } else
- lq->agg_ctrl.requested_ba &= ~tid_msk;
- }
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- out:
- return;
-}
-
-static void iwl4965_bg_agg_work(struct work_struct *work)
-{
- struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv,
- agg_work);
-
- u32 tid;
- u32 retry_tid;
- u32 tid_msk;
- unsigned long flags;
- struct iwl4965_lq_mngr *lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
-
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- retry_tid = lq->agg_ctrl.tid_retry;
- lq->agg_ctrl.tid_retry = 0;
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
-
- if (retry_tid == TID_ALL_SPECIFIED)
- iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED);
- else {
- for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
- tid_msk = (1 << tid);
- if (retry_tid & tid_msk)
- iwl4965_turn_on_agg(priv, tid);
- }
- }
-
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- if (lq->agg_ctrl.tid_retry)
- lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500);
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- return;
-}
-
-/* TODO: move this functionality to rate scaling */
-void iwl4965_tl_get_stats(struct iwl4965_priv *priv,
- struct ieee80211_hdr *hdr)
-{
- __le16 *qc = ieee80211_get_qos_ctrl(hdr);
-
- if (qc &&
- (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) {
- u8 tid = 0;
- tid = (u8) (le16_to_cpu(*qc) & 0xF);
- if (tid < TID_MAX_LOAD_COUNT)
- iwl4965_tl_add_packet(priv, tid);
- }
-
- if (priv->lq_mngr.agg_ctrl.next_retry &&
- (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) {
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lq_mngr.lock, flags);
- priv->lq_mngr.agg_ctrl.next_retry = 0;
- spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
- schedule_work(&priv->agg_work);
- }
-}
-
-#endif /*CONFIG_IWL4965_HT_AGG */
-#endif /* CONFIG_IWL4965_HT */
-
/**
* sign_extend - Sign extend a value using specified bit as sign-bit
*
{
s8 signal = stats->ssi;
s8 noise = 0;
- int rate = stats->rate;
+ int rate = stats->rate_idx;
u64 tsf = stats->mactime;
__le16 phy_flags_hw = rx_start->phy_flags;
struct iwl4965_rt_rx_hdr {
IEEE80211_CHAN_2GHZ),
&iwl4965_rt->rt_chbitmask);
- rate = iwl4965_rate_index_from_plcp(rate);
if (rate == -1)
iwl4965_rt->rt_rate = 0;
else
return 0;
}
-void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, int mode)
+void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info,
+ enum ieee80211_band band)
{
ht_info->cap = 0;
memset(ht_info->supp_mcs_set, 0, 16);
ht_info->ht_supported = 1;
- if (mode == MODE_IEEE80211A) {
+ if (band == IEEE80211_BAND_5GHZ) {
ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
ht_info->supp_mcs_set[4] = 0x01;
}
}
}
+#ifdef CONFIG_IWL4965_DEBUG
+
+/**
+ * iwl4965_dbg_report_frame - dump frame to syslog during debug sessions
+ *
+ * You may hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ *
+ * TODO: This was originally written for 3945, need to audit for
+ * proper operation with 4965.
+ */
+static void iwl4965_dbg_report_frame(struct iwl4965_priv *priv,
+ struct iwl4965_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100)
+{
+ u32 to_us;
+ u32 print_summary = 0;
+ u32 print_dump = 0; /* set to 1 to dump all frames' contents */
+ u32 hundred = 0;
+ u32 dataframe = 0;
+ u16 fc;
+ u16 seq_ctl;
+ u16 channel;
+ u16 phy_flags;
+ int rate_sym;
+ u16 length;
+ u16 status;
+ u16 bcn_tmr;
+ u32 tsf_low;
+ u64 tsf;
+ u8 rssi;
+ u8 agc;
+ u16 sig_avg;
+ u16 noise_diff;
+ struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+ struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ u8 *data = IWL_RX_DATA(pkt);
+
+ if (likely(!(iwl4965_debug_level & IWL_DL_RX)))
+ return;
+
+ /* MAC header */
+ fc = le16_to_cpu(header->frame_control);
+ seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+ /* metadata */
+ channel = le16_to_cpu(rx_hdr->channel);
+ phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+ rate_sym = rx_hdr->rate;
+ length = le16_to_cpu(rx_hdr->len);
+
+ /* end-of-frame status and timestamp */
+ status = le32_to_cpu(rx_end->status);
+ bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+ tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+ tsf = le64_to_cpu(rx_end->timestamp);
+
+ /* signal statistics */
+ rssi = rx_stats->rssi;
+ agc = rx_stats->agc;
+ sig_avg = le16_to_cpu(rx_stats->sig_avg);
+ noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+ to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+ /* if data frame is to us and all is good,
+ * (optionally) print summary for only 1 out of every 100 */
+ if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+ dataframe = 1;
+ if (!group100)
+ print_summary = 1; /* print each frame */
+ else if (priv->framecnt_to_us < 100) {
+ priv->framecnt_to_us++;
+ print_summary = 0;
+ } else {
+ priv->framecnt_to_us = 0;
+ print_summary = 1;
+ hundred = 1;
+ }
+ } else {
+ /* print summary for all other frames */
+ print_summary = 1;
+ }
+
+ if (print_summary) {
+ char *title;
+ int rate_idx;
+ u32 bitrate;
+
+ if (hundred)
+ title = "100Frames";
+ else if (fc & IEEE80211_FCTL_RETRY)
+ title = "Retry";
+ else if (ieee80211_is_assoc_response(fc))
+ title = "AscRsp";
+ else if (ieee80211_is_reassoc_response(fc))
+ title = "RasRsp";
+ else if (ieee80211_is_probe_response(fc)) {
+ title = "PrbRsp";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_beacon(fc)) {
+ title = "Beacon";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_atim(fc))
+ title = "ATIM";
+ else if (ieee80211_is_auth(fc))
+ title = "Auth";
+ else if (ieee80211_is_deauth(fc))
+ title = "DeAuth";
+ else if (ieee80211_is_disassoc(fc))
+ title = "DisAssoc";
+ else
+ title = "Frame";
+
+ rate_idx = iwl4965_hwrate_to_plcp_idx(rate_sym);
+ if (unlikely(rate_idx == -1))
+ bitrate = 0;
+ else
+ bitrate = iwl4965_rates[rate_idx].ieee / 2;
+
+ /* print frame summary.
+ * MAC addresses show just the last byte (for brevity),
+ * but you can hack it to show more, if you'd like to. */
+ if (dataframe)
+ IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+ "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+ title, fc, header->addr1[5],
+ length, rssi, channel, bitrate);
+ else {
+ /* src/dst addresses assume managed mode */
+ IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+ "src=0x%02x, rssi=%u, tim=%lu usec, "
+ "phy=0x%02x, chnl=%d\n",
+ title, fc, header->addr1[5],
+ header->addr3[5], rssi,
+ tsf_low - priv->scan_start_tsf,
+ phy_flags, channel);
+ }
+ }
+ if (print_dump)
+ iwl4965_print_hex_dump(IWL_DL_RX, data, length);
+}
+#else
+static inline void iwl4965_dbg_report_frame(struct iwl4965_priv *priv,
+ struct iwl4965_rx_packet *pkt,
+ struct ieee80211_hdr *header,
+ int group100)
+{
+}
+#endif
+
#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv,
struct iwl4965_rx_mem_buffer *rxb)
{
+ struct ieee80211_hdr *header;
+ struct ieee80211_rx_status rx_status;
struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
/* Use phy data (Rx signal strength, etc.) contained within
* this rx packet for legacy frames,
(struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
__le32 *rx_end;
unsigned int len = 0;
- struct ieee80211_hdr *header;
u16 fc;
- struct ieee80211_rx_status stats = {
- .mactime = le64_to_cpu(rx_start->timestamp),
- .channel = le16_to_cpu(rx_start->channel),
- .phymode =
- (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
- MODE_IEEE80211G : MODE_IEEE80211A,
- .antenna = 0,
- .rate = iwl4965_hw_get_rate(rx_start->rate_n_flags),
- .flag = 0,
- };
u8 network_packet;
+ rx_status.mactime = le64_to_cpu(rx_start->timestamp);
+ rx_status.freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel));
+ rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ rx_status.rate_idx = iwl4965_hwrate_to_plcp_idx(
+ le32_to_cpu(rx_start->rate_n_flags));
+
+ if (rx_status.band == IEEE80211_BAND_5GHZ)
+ rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
+
+ rx_status.antenna = 0;
+ rx_status.flag = 0;
+
if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
IWL_DEBUG_DROP
("dsp size out of range [0,20]: "
"%d/n", rx_start->cfg_phy_cnt);
return;
}
+
if (!include_phy) {
if (priv->last_phy_res[0])
rx_start = (struct iwl4965_rx_phy_res *)
+ rx_start->cfg_phy_cnt);
len = le16_to_cpu(rx_start->byte_count);
- rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt +
+ rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt +
sizeof(struct iwl4965_rx_phy_res) + len);
} else {
struct iwl4965_rx_mpdu_res_start *amsdu =
priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
- stats.freq = ieee80211chan2mhz(stats.channel);
-
/* Find max signal strength (dBm) among 3 antenna/receiver chains */
- stats.ssi = iwl4965_calc_rssi(rx_start);
+ rx_status.ssi = iwl4965_calc_rssi(rx_start);
/* Meaningful noise values are available only from beacon statistics,
* which are gathered only when associated, and indicate noise
* Ignore these noise values while scanning (other channels) */
if (iwl4965_is_associated(priv) &&
!test_bit(STATUS_SCANNING, &priv->status)) {
- stats.noise = priv->last_rx_noise;
- stats.signal = iwl4965_calc_sig_qual(stats.ssi, stats.noise);
+ rx_status.noise = priv->last_rx_noise;
+ rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi,
+ rx_status.noise);
} else {
- stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
- stats.signal = iwl4965_calc_sig_qual(stats.ssi, 0);
+ rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+ rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0);
}
/* Reset beacon noise level if not associated. */
if (!iwl4965_is_associated(priv))
priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-#ifdef CONFIG_IWL4965_DEBUG
- /* TODO: Parts of iwl4965_report_frame are broken for 4965 */
- if (iwl4965_debug_level & (IWL_DL_RX))
- /* Set "1" to report good data frames in groups of 100 */
- iwl4965_report_frame(priv, pkt, header, 1);
-
- if (iwl4965_debug_level & (IWL_DL_RX | IWL_DL_STATS))
- IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n",
- stats.ssi, stats.noise, stats.signal,
- (long unsigned int)le64_to_cpu(rx_start->timestamp));
-#endif
+ /* Set "1" to report good data frames in groups of 100 */
+ /* FIXME: need to optimze the call: */
+ iwl4965_dbg_report_frame(priv, pkt, header, 1);
+
+ IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n",
+ rx_status.ssi, rx_status.noise, rx_status.signal,
+ rx_status.mactime);
network_packet = iwl4965_is_network_packet(priv, header);
if (network_packet) {
- priv->last_rx_rssi = stats.ssi;
+ priv->last_rx_rssi = rx_status.ssi;
priv->last_beacon_time = priv->ucode_beacon_time;
priv->last_tsf = le64_to_cpu(rx_start->timestamp);
}
return;
}
}
- iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats);
+ iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status);
break;
case IEEE80211_FTYPE_CTL:
case IEEE80211_STYPE_BACK_REQ:
IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n");
iwl4965_handle_data_packet(priv, 0, include_phy,
- rxb, &stats);
+ rxb, &rx_status);
break;
default:
break;
print_mac(mac3, header->addr3));
else
iwl4965_handle_data_packet(priv, 1, include_phy, rxb,
- &stats);
+ &rx_status);
break;
}
default:
}
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
-
-/**
- * iwl4965_set_tx_status - Update driver's record of one Tx frame's status
- *
- * This will get sent to mac80211.
- */
-static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx,
- u32 status, u32 retry_count, u32 rate)
-{
- struct ieee80211_tx_status *tx_status =
- &(priv->txq[txq_id].txb[idx].status);
-
- tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0;
- tx_status->retry_count += retry_count;
- tx_status->control.tx_rate = rate;
-}
-
/**
* iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
-
/**
* iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack
*
{
int i, sh, ack;
- u16 ba_seq_ctl = le16_to_cpu(ba_resp->ba_seq_ctl);
- u32 bitmap0, bitmap1;
- u32 resp_bitmap0 = le32_to_cpu(ba_resp->ba_bitmap0);
- u32 resp_bitmap1 = le32_to_cpu(ba_resp->ba_bitmap1);
+ u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
+ u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
+ u64 bitmap;
+ int successes = 0;
+ struct ieee80211_tx_status *tx_status;
if (unlikely(!agg->wait_for_ba)) {
IWL_ERROR("Received BA when not expected\n");
/* Mark that the expected block-ack response arrived */
agg->wait_for_ba = 0;
- IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl);
+ IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
/* Calculate shift to align block-ack bits with our Tx window bits */
- sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl >> 4);
+ sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4);
if (sh < 0) /* tbw something is wrong with indices */
sh += 0x100;
/* don't use 64-bit values for now */
- bitmap0 = resp_bitmap0 >> sh;
- bitmap1 = resp_bitmap1 >> sh;
- bitmap0 |= (resp_bitmap1 & ((1 << sh) | ((1 << sh) - 1))) << (32 - sh);
+ bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
if (agg->frame_count > (64 - sh)) {
IWL_DEBUG_TX_REPLY("more frames than bitmap size");
/* check for success or failure according to the
* transmitted bitmap and block-ack bitmap */
- bitmap0 &= agg->bitmap0;
- bitmap1 &= agg->bitmap1;
+ bitmap &= agg->bitmap;
/* For each frame attempted in aggregation,
* update driver's record of tx frame's status. */
for (i = 0; i < agg->frame_count ; i++) {
- int idx = (agg->start_idx + i) & 0xff;
- ack = bitmap0 & (1 << i);
+ ack = bitmap & (1 << i);
+ successes += !!ack;
IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
- ack? "ACK":"NACK", i, idx, agg->start_idx + i);
- iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0,
- agg->rate_n_flags);
+ ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff,
+ agg->start_idx + i);
+ }
+ tx_status = &priv->txq[scd_flow].txb[agg->start_idx].status;
+ tx_status->flags = IEEE80211_TX_STATUS_ACK;
+ tx_status->flags |= IEEE80211_TX_STATUS_AMPDU;
+ tx_status->ampdu_ack_map = successes;
+ tx_status->ampdu_ack_len = agg->frame_count;
+ iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags,
+ &tx_status->control);
+
+ IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap);
+
+ return 0;
+}
+
+/**
+ * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration
+ */
+static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv,
+ u16 txq_id)
+{
+ /* Simply stop the queue, but don't change any configuration;
+ * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
+ iwl4965_write_prph(priv,
+ KDR_SCD_QUEUE_STATUS_BITS(txq_id),
+ (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+ (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+/**
+ * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ * priv->lock must be held by the caller
+ */
+static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id,
+ u16 ssn_idx, u8 tx_fifo)
+{
+ int ret = 0;
+
+ if (IWL_BACK_QUEUE_FIRST_ID > txq_id) {
+ IWL_WARNING("queue number too small: %d, must be > %d\n",
+ txq_id, IWL_BACK_QUEUE_FIRST_ID);
+ return -EINVAL;
}
- IWL_DEBUG_TX_REPLY("Bitmap %x%x\n", bitmap0, bitmap1);
+ ret = iwl4965_grab_nic_access(priv);
+ if (ret)
+ return ret;
+
+ iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+ iwl4965_clear_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id));
+
+ priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+ priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+ /* supposes that ssn_idx is valid (!= 0xFFF) */
+ iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+ iwl4965_clear_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id));
+ iwl4965_txq_ctx_deactivate(priv, txq_id);
+ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
+
+ iwl4965_release_nic_access(priv);
return 0;
}
+int iwl4965_check_empty_hw_queue(struct iwl4965_priv *priv, int sta_id,
+ u8 tid, int txq_id)
+{
+ struct iwl4965_queue *q = &priv->txq[txq_id].q;
+ u8 *addr = priv->stations[sta_id].sta.sta.addr;
+ struct iwl4965_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+
+ switch (priv->stations[sta_id].tid[tid].agg.state) {
+ case IWL_EMPTYING_HW_QUEUE_DELBA:
+ /* We are reclaiming the last packet of the */
+ /* aggregated HW queue */
+ if (txq_id == tid_data->agg.txq_id &&
+ q->read_ptr == q->write_ptr) {
+ u16 ssn = SEQ_TO_SN(tid_data->seq_number);
+ int tx_fifo = default_tid_to_tx_fifo[tid];
+ IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
+ iwl4965_tx_queue_agg_disable(priv, txq_id,
+ ssn, tx_fifo);
+ tid_data->agg.state = IWL_AGG_OFF;
+ ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
+ }
+ break;
+ case IWL_EMPTYING_HW_QUEUE_ADDBA:
+ /* We are reclaiming the last packet of the queue */
+ if (tid_data->tfds_in_queue == 0) {
+ IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n");
+ tid_data->agg.state = IWL_AGG_ON;
+ ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
+ }
+ break;
+ }
+ return 0;
+}
+
/**
* iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed
* @index -- current index
int index;
struct iwl4965_tx_queue *txq = NULL;
struct iwl4965_ht_agg *agg;
+ DECLARE_MAC_BUF(mac);
/* "flow" corresponds to Tx queue */
- u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow);
+ u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
/* "ssn" is start of block-ack Tx window, corresponds to index
* (in Tx queue's circular buffer) of first TFD/frame in window */
u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
- if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) {
+ if (scd_flow >= ARRAY_SIZE(priv->txq)) {
IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
return;
}
- txq = &priv->txq[ba_resp_scd_flow];
+ txq = &priv->txq[scd_flow];
agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
/* Find index just before block-ack window */
index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
/* TODO: Need to get this copy more safely - now good for debug */
-/*
- {
- DECLARE_MAC_BUF(mac);
+
IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, "
"sta_id = %d\n",
agg->wait_for_ba,
print_mac(mac, (u8*) &ba_resp->sta_addr_lo32),
ba_resp->sta_id);
- IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = "
+ IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
"%d, scd_ssn = %d\n",
ba_resp->tid,
- ba_resp->ba_seq_ctl,
- ba_resp->ba_bitmap1,
- ba_resp->ba_bitmap0,
+ ba_resp->seq_ctl,
+ (unsigned long long)le64_to_cpu(ba_resp->bitmap),
ba_resp->scd_flow,
ba_resp->scd_ssn);
- IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%X%X \n",
+ IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n",
agg->start_idx,
- agg->bitmap1,
- agg->bitmap0);
- }
-*/
+ (unsigned long long)agg->bitmap);
/* Update driver's record of ACK vs. not for each frame in window */
iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp);
/* Release all TFDs before the SSN, i.e. all TFDs in front of
* block-ack window (we assume that they've been successfully
* transmitted ... if not, it's too late anyway). */
- if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff))
- iwl4965_tx_queue_reclaim(priv, ba_resp_scd_flow, index);
-
-}
-
-
-/**
- * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration
- */
-static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv, u16 txq_id)
-{
- /* Simply stop the queue, but don't change any configuration;
- * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
- iwl4965_write_prph(priv,
- KDR_SCD_QUEUE_STATUS_BITS(txq_id),
- (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
- (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+ if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
+ int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index);
+ priv->stations[ba_resp->sta_id].
+ tid[ba_resp->tid].tfds_in_queue -= freed;
+ if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
+ priv->mac80211_registered &&
+ agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
+ ieee80211_wake_queue(priv->hw, scd_flow);
+ iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id,
+ ba_resp->tid, scd_flow);
+ }
}
/**
return 0;
}
+
/**
* iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue
*
return 0;
}
-/**
- * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
- */
-static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id,
- u16 ssn_idx, u8 tx_fifo)
-{
- unsigned long flags;
- int rc;
-
- if (IWL_BACK_QUEUE_FIRST_ID > txq_id) {
- IWL_WARNING("queue number too small: %d, must be > %d\n",
- txq_id, IWL_BACK_QUEUE_FIRST_ID);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
- rc = iwl4965_grab_nic_access(priv);
- if (rc) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
- }
-
- iwl4965_tx_queue_stop_scheduler(priv, txq_id);
-
- iwl4965_clear_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id));
-
- priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
- priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
- /* supposes that ssn_idx is valid (!= 0xFFF) */
- iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
-
- iwl4965_clear_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id));
- iwl4965_txq_ctx_deactivate(priv, txq_id);
- iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
-
- iwl4965_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-#endif/* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
/**
* all the way down to 1M in IEEE order, and then spin on 1M */
if (is_ap)
r = IWL_RATE_54M_INDEX;
- else if (priv->phymode == MODE_IEEE80211A)
+ else if (priv->band == IEEE80211_BAND_5GHZ)
r = IWL_RATE_6M_INDEX;
else
r = IWL_RATE_1M_INDEX;
link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
/* Update the rate scaling for control frame Tx to AP */
- link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID;
+ link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_setting.bcast_sta_id;
iwl4965_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
&link_cmd);
#ifdef CONFIG_IWL4965_HT
-static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, int phymode,
- u16 channel, u8 extension_chan_offset)
+static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv,
+ enum ieee80211_band band,
+ u16 channel, u8 extension_chan_offset)
{
const struct iwl4965_channel_info *ch_info;
- ch_info = iwl4965_get_channel_info(priv, phymode, channel);
+ ch_info = iwl4965_get_channel_info(priv, band, channel);
if (!is_channel_valid(ch_info))
return 0;
- if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
+ if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)
return 0;
if ((ch_info->fat_extension_channel == extension_chan_offset) ||
if ((!iwl_ht_conf->is_ht) ||
(iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
- (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO))
+ (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE))
return 0;
if (sta_ht_inf) {
if ((!sta_ht_inf->ht_supported) ||
- (!sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))
+ (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
return 0;
}
- return (iwl4965_is_channel_extension(priv, priv->phymode,
+ return (iwl4965_is_channel_extension(priv, priv->band,
iwl_ht_conf->control_channel,
iwl_ht_conf->extension_chan_offset));
}
case IWL_EXT_CHANNEL_OFFSET_BELOW:
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
break;
- case IWL_EXT_CHANNEL_OFFSET_AUTO:
- rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
- break;
+ case IWL_EXT_CHANNEL_OFFSET_NONE:
default:
rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
break;
iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
-int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
- enum ieee80211_ampdu_mlme_action action,
- const u8 *addr, u16 tid, u16 ssn)
-{
- struct iwl4965_priv *priv = hw->priv;
- int sta_id;
- DECLARE_MAC_BUF(mac);
-
- IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ",
- print_mac(mac, addr), tid);
- sta_id = iwl4965_hw_find_station(priv, addr);
- switch (action) {
- case IEEE80211_AMPDU_RX_START:
- IWL_DEBUG_HT("start Rx\n");
- iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, ssn);
- break;
- case IEEE80211_AMPDU_RX_STOP:
- IWL_DEBUG_HT("stop Rx\n");
- iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
- break;
- default:
- IWL_DEBUG_HT("unknown\n");
- return -EINVAL;
- break;
- }
- return 0;
-}
-
-#ifdef CONFIG_IWL4965_HT_AGG
-
-static const u16 default_tid_to_tx_fifo[] = {
- IWL_TX_FIFO_AC1,
- IWL_TX_FIFO_AC0,
- IWL_TX_FIFO_AC0,
- IWL_TX_FIFO_AC1,
- IWL_TX_FIFO_AC2,
- IWL_TX_FIFO_AC2,
- IWL_TX_FIFO_AC3,
- IWL_TX_FIFO_AC3,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_AC3
-};
-
/*
* Find first available (lowest unused) Tx Queue, mark it "active".
* Called only when finding queue for aggregation.
return -1;
}
-int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid,
- u16 *start_seq_num)
+static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da,
+ u16 tid, u16 *start_seq_num)
{
-
struct iwl4965_priv *priv = hw->priv;
int sta_id;
int tx_fifo;
int txq_id;
int ssn = -1;
+ int ret = 0;
unsigned long flags;
struct iwl4965_tid_data *tid_data;
DECLARE_MAC_BUF(mac);
- /* Determine Tx DMA/FIFO channel for this Traffic ID */
if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
tx_fifo = default_tid_to_tx_fifo[tid];
else
return -EINVAL;
- IWL_WARNING("iwl-AGG iwl4965_mac_ht_tx_agg_start on da=%s"
- " tid=%d\n", print_mac(mac, da), tid);
+ IWL_WARNING("%s on da = %s tid = %d\n",
+ __func__, print_mac(mac, da), tid);
- /* Get index into station table */
sta_id = iwl4965_hw_find_station(priv, da);
if (sta_id == IWL_INVALID_STATION)
return -ENXIO;
- /* Find available Tx queue for aggregation */
+ if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
+ IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n");
+ return -ENXIO;
+ }
+
txq_id = iwl4965_txq_ctx_activate_free(priv);
if (txq_id == -1)
return -ENXIO;
spin_lock_irqsave(&priv->sta_lock, flags);
tid_data = &priv->stations[sta_id].tid[tid];
-
- /* Get starting sequence number for 1st frame in block ack window.
- * We'll use least signif byte as 1st frame's index into Tx queue. */
ssn = SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
spin_unlock_irqrestore(&priv->sta_lock, flags);
*start_seq_num = ssn;
+ ret = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
+ sta_id, tid, ssn);
+ if (ret)
+ return ret;
- /* Update driver's link quality manager */
- iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE);
-
- /* Set up and enable aggregation for selected Tx queue and FIFO */
- return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
- sta_id, tid, ssn);
+ ret = 0;
+ if (tid_data->tfds_in_queue == 0) {
+ printk(KERN_ERR "HW queue is empty\n");
+ tid_data->agg.state = IWL_AGG_ON;
+ ieee80211_start_tx_ba_cb_irqsafe(hw, da, tid);
+ } else {
+ IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n",
+ tid_data->tfds_in_queue);
+ tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+ }
+ return ret;
}
-
-int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
- int generator)
+static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da,
+ u16 tid)
{
struct iwl4965_priv *priv = hw->priv;
int tx_fifo_id, txq_id, sta_id, ssn = -1;
struct iwl4965_tid_data *tid_data;
- int rc;
+ int ret, write_ptr, read_ptr;
+ unsigned long flags;
DECLARE_MAC_BUF(mac);
if (!da) {
- IWL_ERROR("%s: da = NULL\n", __func__);
+ IWL_ERROR("da = NULL\n");
return -EINVAL;
}
if (sta_id == IWL_INVALID_STATION)
return -ENXIO;
+ if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
+ IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n");
+
tid_data = &priv->stations[sta_id].tid[tid];
ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
txq_id = tid_data->agg.txq_id;
+ write_ptr = priv->txq[txq_id].q.write_ptr;
+ read_ptr = priv->txq[txq_id].q.read_ptr;
+
+ /* The queue is not empty */
+ if (write_ptr != read_ptr) {
+ IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n");
+ priv->stations[sta_id].tid[tid].agg.state =
+ IWL_EMPTYING_HW_QUEUE_DELBA;
+ return 0;
+ }
- rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
- /* FIXME: need more safe way to handle error condition */
- if (rc)
- return rc;
+ IWL_DEBUG_HT("HW queue empty\n");;
+ priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (ret)
+ return ret;
+
+ ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, da, tid);
- iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA);
IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n",
- print_mac(mac, da), tid);
+ print_mac(mac, da), tid);
return 0;
}
+int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+ enum ieee80211_ampdu_mlme_action action,
+ const u8 *addr, u16 tid, u16 *ssn)
+{
+ struct iwl4965_priv *priv = hw->priv;
+ int sta_id;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ",
+ print_mac(mac, addr), tid);
+ sta_id = iwl4965_hw_find_station(priv, addr);
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ IWL_DEBUG_HT("start Rx\n");
+ iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, *ssn);
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ IWL_DEBUG_HT("stop Rx\n");
+ iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ IWL_DEBUG_HT("start Tx\n");
+ return iwl4965_mac_ht_tx_agg_start(hw, addr, tid, ssn);
+ case IEEE80211_AMPDU_TX_STOP:
+ IWL_DEBUG_HT("stop Tx\n");
+ return iwl4965_mac_ht_tx_agg_stop(hw, addr, tid);
+ default:
+ IWL_DEBUG_HT("unknown\n");
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
-#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
/* Set up 4965-specific Rx frame reply handlers */
iwl4965_rx_missed_beacon_notif;
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
-#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
}
#ifdef CONFIG_IWL4965_SENSITIVITY
INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
#endif
-#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
- INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work);
-#endif /* CONFIG_IWL4965_HT_AGG */
-#endif /* CONFIG_IWL4965_HT */
init_timer(&priv->statistics_periodic);
priv->statistics_periodic.data = (unsigned long)priv;
priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
cancel_delayed_work(&priv->init_alive_start);
}
-struct pci_device_id iwl4965_hw_card_ids[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4229)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4230)},
- {0}
+static struct iwl_lib_ops iwl4965_lib = {
+ .eeprom_ops = {
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ },
};
-/*
- * The device's EEPROM semaphore prevents conflicts between driver and uCode
- * when accessing the EEPROM; each access is a series of pulses to/from the
- * EEPROM chip, not a single event, so even reads could conflict if they
- * weren't arbitrated by the semaphore.
- */
-int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv)
-{
- u16 count;
- int rc;
+static struct iwl_ops iwl4965_ops = {
+ .lib = &iwl4965_lib,
+};
- for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
- /* Request semaphore */
- iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
- /* See if we got it */
- rc = iwl4965_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
- EEPROM_SEM_TIMEOUT);
- if (rc >= 0) {
- IWL_DEBUG_IO("Acquired semaphore after %d tries.\n",
- count+1);
- return rc;
- }
- }
+static struct iwl_cfg iwl4965_agn_cfg = {
+ .name = "4965AGN",
+ .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl4965_ops,
+};
- return rc;
-}
+struct pci_device_id iwl4965_hw_card_ids[] = {
+ {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
+ {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
+ {0}
+};
MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids);
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
extern struct pci_device_id iwl4965_hw_card_ids[];
#define DRV_NAME "iwl4965"
+#include "iwl-eeprom.h"
#include "iwl-4965-hw.h"
+#include "iwl-csr.h"
#include "iwl-prph.h"
#include "iwl-4965-debug.h"
+/* Change firmware file name, using "-" and incrementing number,
+ * *only* when uCode interface or architecture changes so that it
+ * is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL4965_UCODE_API "-1"
+
+
/* Default noise level to report when noise measurement is not available.
* This may be because we're:
* 1) Not associated (4965, no beacon statistics being sent to driver)
u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */
u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */
- u8 phymode; /* MODE_IEEE80211{A,B,G} */
+ enum ieee80211_band band;
/* Radio/DSP gain settings for each "normal" data Tx rate.
* These include, in addition to RF and DSP gain, a few fields for
#define IWL_INVALID_VALUE -1
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
/**
* struct iwl4965_ht_agg -- aggregation status while waiting for block-ack
* @txq_id: Tx queue used for Tx attempt
u16 frame_count;
u16 wait_for_ba;
u16 start_idx;
- u32 bitmap0;
- u32 bitmap1;
+ u64 bitmap;
u32 rate_n_flags;
+#define IWL_AGG_OFF 0
+#define IWL_AGG_ON 1
+#define IWL_EMPTYING_HW_QUEUE_ADDBA 2
+#define IWL_EMPTYING_HW_QUEUE_DELBA 3
+ u8 state;
};
-#endif /* CONFIG_IWL4965_HT_AGG */
+
#endif /* CONFIG_IWL4965_HT */
struct iwl4965_tid_data {
u16 seq_number;
+ u16 tfds_in_queue;
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
struct iwl4965_ht_agg agg;
-#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
};
};
#endif /*CONFIG_IWL4965_HT */
-#ifdef CONFIG_IWL4965_QOS
-
union iwl4965_qos_capabity {
struct {
u8 edca_count:4; /* bit 0-3 */
union iwl4965_qos_capabity qos_cap;
struct iwl4965_qosparam_cmd def_qos_parm;
};
-#endif /*CONFIG_IWL4965_QOS */
#define STA_PS_STATUS_WAKE 0
#define STA_PS_STATUS_SLEEP 1
/**
* struct iwl4965_driver_hw_info
* @max_txq_num: Max # Tx queues supported
- * @ac_queue_count: # Tx queues for EDCA Access Categories (AC)
* @tx_cmd_len: Size of Tx command (but not including frame itself)
+ * @tx_ant_num: Number of TX antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
* @rx_buffer_size:
* @max_rxq_log: Log-base-2 of max_rxq_size
*/
struct iwl4965_driver_hw_info {
u16 max_txq_num;
- u16 ac_queue_count;
u16 tx_cmd_len;
+ u16 tx_ant_num;
u16 max_rxq_size;
u32 rx_buf_size;
u32 max_pkt_size;
extern int iwl4965_is_network_packet(struct iwl4965_priv *priv,
struct ieee80211_hdr *header);
extern int iwl4965_power_init_handle(struct iwl4965_priv *priv);
-extern int iwl4965_eeprom_init(struct iwl4965_priv *priv);
-#ifdef CONFIG_IWL4965_DEBUG
-extern void iwl4965_report_frame(struct iwl4965_priv *priv,
- struct iwl4965_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100);
-#else
-static inline void iwl4965_report_frame(struct iwl4965_priv *priv,
- struct iwl4965_rx_packet *pkt,
- struct ieee80211_hdr *header,
- int group100) {}
-#endif
extern void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv,
struct iwl4965_rx_mem_buffer *rxb,
void *data, short len,
extern int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel);
extern int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index);
-
+extern int iwl4965_queue_space(const struct iwl4965_queue *q);
struct iwl4965_priv;
/*
* Forward declare iwl-4965.c functions for iwl-base.c
*/
-extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv);
-
extern int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv,
struct iwl4965_tx_queue *txq,
u16 byte_cnt);
extern void iwl4965_chain_noise_reset(struct iwl4965_priv *priv);
extern void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags,
u8 force);
-extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode,
+extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv,
+ enum ieee80211_band band,
u16 channel,
const struct iwl4965_eeprom_channel *eeprom_ch,
u8 fat_extension_channel);
extern void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv);
+extern void iwl4965_hwrate_to_tx_control(struct iwl4965_priv *priv,
+ u32 rate_n_flags,
+ struct ieee80211_tx_control *control);
#ifdef CONFIG_IWL4965_HT
-extern void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info,
- int mode);
-extern void iwl4965_set_rxon_ht(struct iwl4965_priv *priv,
- struct iwl_ht_info *ht_info);
-extern void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
+void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info,
+ enum ieee80211_band band);
+void iwl4965_set_rxon_ht(struct iwl4965_priv *priv,
+ struct iwl_ht_info *ht_info);
+void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
struct ieee80211_ht_info *sta_ht_inf);
-extern int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
- const u8 *addr, u16 tid, u16 ssn);
-#ifdef CONFIG_IWL4965_HT_AGG
-extern int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da,
- u16 tid, u16 *start_seq_num);
-extern int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da,
- u16 tid, int generator);
-extern void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid);
-extern void iwl4965_tl_get_stats(struct iwl4965_priv *priv,
- struct ieee80211_hdr *hdr);
-#endif /* CONFIG_IWL4965_HT_AGG */
+ const u8 *addr, u16 tid, u16 *ssn);
+int iwl4965_check_empty_hw_queue(struct iwl4965_priv *priv, int sta_id,
+ u8 tid, int txq_id);
+#else
+static inline void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info,
+ enum ieee80211_band band) {}
+
#endif /*CONFIG_IWL4965_HT */
/* Structures, enum, and defines specific to the 4965 */
size_t size;
};
-#define TID_QUEUE_CELL_SPACING 50 /*mS */
-#define TID_QUEUE_MAX_SIZE 20
-#define TID_ROUND_VALUE 5 /* mS */
-#define TID_MAX_LOAD_COUNT 8
-
-#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
-#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
-
-#define TID_ALL_ENABLED 0x7f
-#define TID_ALL_SPECIFIED 0xff
-#define TID_AGG_TPT_THREHOLD 0x0
-
#define IWL_CHANNEL_WIDTH_20MHZ 0
#define IWL_CHANNEL_WIDTH_40MHZ 1
#define IWL_OPERATION_MODE_MIXED 2
#define IWL_OPERATION_MODE_20MHZ 3
-#define IWL_EXT_CHANNEL_OFFSET_AUTO 0
-#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1
-#define IWL_EXT_CHANNEL_OFFSET_ 2
-#define IWL_EXT_CHANNEL_OFFSET_BELOW 3
-#define IWL_EXT_CHANNEL_OFFSET_MAX 4
+#define IWL_EXT_CHANNEL_OFFSET_NONE 0
+#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1
+#define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2
+#define IWL_EXT_CHANNEL_OFFSET_BELOW 3
#define NRG_NUM_PREV_STAT_L 20
#define NUM_RX_CHAINS (3)
#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
-struct iwl4965_traffic_load {
- unsigned long time_stamp;
- u32 packet_count[TID_QUEUE_MAX_SIZE];
- u8 queue_count;
- u8 head;
- u32 total;
-};
-
-#ifdef CONFIG_IWL4965_HT_AGG
-/**
- * struct iwl4965_agg_control
- * @requested_ba: bit map of tids requesting aggregation/block-ack
- * @granted_ba: bit map of tids granted aggregation/block-ack
- */
-struct iwl4965_agg_control {
- unsigned long next_retry;
- u32 wait_for_agg_status;
- u32 tid_retry;
- u32 requested_ba;
- u32 granted_ba;
- u8 auto_agg;
- u32 tid_traffic_load_threshold;
- u32 ba_timeout;
- struct iwl4965_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
-};
-#endif /*CONFIG_IWL4965_HT_AGG */
-
struct iwl4965_lq_mngr {
-#ifdef CONFIG_IWL4965_HT_AGG
- struct iwl4965_agg_control agg_ctrl;
-#endif
spinlock_t lock;
s32 max_window_size;
s32 *expected_tpt;
u8 lq_ready;
};
-
/* Sensitivity and chain noise calibration */
#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
#define INITIALIZATION_VALUE 0xFFFF
struct ieee80211_hw *hw;
struct ieee80211_channel *ieee_channels;
struct ieee80211_rate *ieee_rates;
+ struct iwl_cfg *cfg;
/* temporary frame storage list */
struct list_head free_frames;
int frames_count;
- u8 phymode;
+ enum ieee80211_band band;
int alloc_rxb_skb;
bool add_radiotap;
void (*rx_handlers[REPLY_MAX])(struct iwl4965_priv *priv,
struct iwl4965_rx_mem_buffer *rxb);
- const struct ieee80211_hw_mode *modes;
+ struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
/* spectrum measurement report caching */
u32 scd_base_addr; /* scheduler sram base address */
unsigned long status;
- u32 config;
int last_rx_rssi; /* From Rx packet statisitics */
int last_rx_noise; /* From beacon statistics */
int is_open;
u8 mac80211_registered;
- int is_abg;
u32 notif_missed_beacons;
u16 assoc_capability;
u8 ps_mode;
-#ifdef CONFIG_IWL4965_QOS
struct iwl4965_qos_info qos_data;
-#endif /*CONFIG_IWL4965_QOS */
struct workqueue_struct *workqueue;
#endif
struct work_struct statistics_work;
struct timer_list statistics_periodic;
-
-#ifdef CONFIG_IWL4965_HT_AGG
- struct work_struct agg_work;
-#endif
-}; /*iwl4965_priv */
+}; /*iwl4965_priv */
static inline int iwl4965_is_associated(struct iwl4965_priv *priv)
{
static inline u8 is_channel_a_band(const struct iwl4965_channel_info *ch_info)
{
- return ch_info->phymode == MODE_IEEE80211A;
+ return ch_info->band == IEEE80211_BAND_5GHZ;
}
static inline u8 is_channel_bg_band(const struct iwl4965_channel_info *ch_info)
{
- return ((ch_info->phymode == MODE_IEEE80211B) ||
- (ch_info->phymode == MODE_IEEE80211G));
+ return ch_info->band == IEEE80211_BAND_2GHZ;
}
static inline int is_channel_passive(const struct iwl4965_channel_info *ch)
}
extern const struct iwl4965_channel_info *iwl4965_get_channel_info(
- const struct iwl4965_priv *priv, int phymode, u16 channel);
+ const struct iwl4965_priv *priv, enum ieee80211_band band, u16 channel);
/* Requires full declaration of iwl4965_priv before including */
#include "iwl-4965-io.h"
--- /dev/null
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include "iwl-4965-debug.h"
+#include "iwl-eeprom.h"
+#include "iwl-core.h"
+
+MODULE_DESCRIPTION("iwl core");
+MODULE_VERSION(IWLWIFI_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL/BSD");
+
+#ifdef CONFIG_IWL4965_DEBUG
+u32 iwl4965_debug_level;
+EXPORT_SYMBOL(iwl4965_debug_level);
+#endif
--- /dev/null
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_core_h__
+#define __iwl_core_h__
+
+#define IWLWIFI_VERSION "1.2.26k"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation"
+
+#define IWL_PCI_DEVICE(dev, subdev, cfg) \
+ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
+ .subvendor = PCI_ANY_ID, .subdevice = (subdev), \
+ .driver_data = (kernel_ulong_t)&(cfg)
+
+#define IWL_SKU_G 0x1
+#define IWL_SKU_A 0x2
+#define IWL_SKU_N 0x8
+
+struct iwl_lib_ops {
+ /* eeprom operations (as defined in iwl-eeprom.h) */
+ struct iwl_eeprom_ops eeprom_ops;
+};
+
+struct iwl_ops {
+ const struct iwl_lib_ops *lib;
+};
+
+struct iwl_cfg {
+ const char *name;
+ const char *fw_name;
+ unsigned int sku;
+ const struct iwl_ops *ops;
+};
+
+#endif /* __iwl_core_h__ */
--- /dev/null
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*=== CSR (control and status registers) ===*/
+#define CSR_BASE (0x000)
+
+#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
+#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */
+#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */
+#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/
+#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */
+#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
+#define CSR_GP_CNTRL (CSR_BASE+0x024)
+
+/*
+ * Hardware revision info
+ * Bit fields:
+ * 31-8: Reserved
+ * 7-4: Type of device: 0x0 = 4965, 0xd = 3945
+ * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D
+ * 1-0: "Dash" value, as in A-1, etc.
+ *
+ * NOTE: Revision step affects calculation of CCK txpower for 4965.
+ */
+#define CSR_HW_REV (CSR_BASE+0x028)
+
+/* EEPROM reads */
+#define CSR_EEPROM_REG (CSR_BASE+0x02c)
+#define CSR_EEPROM_GP (CSR_BASE+0x030)
+#define CSR_GP_UCODE (CSR_BASE+0x044)
+#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
+#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
+#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
+#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
+#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
+
+/* Analog phase-lock-loop configuration (3945 only)
+ * Set bit 24. */
+#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
+/*
+ * Indicates hardware rev, to determine CCK backoff for txpower calculation.
+ * Bit fields:
+ * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
+ */
+#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
+
+/* Bits for CSR_HW_IF_CONFIG_REG */
+#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010)
+#define CSR49_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00)
+#define CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
+#define CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200)
+
+#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100)
+#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200)
+#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400)
+#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800)
+#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
+#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)
+
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
+
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */
+#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \
+ CSR_INT_BIT_HW_ERR | \
+ CSR_INT_BIT_FH_TX | \
+ CSR_INT_BIT_SW_ERR | \
+ CSR_INT_BIT_RF_KILL | \
+ CSR_INT_BIT_SW_RX | \
+ CSR_INT_BIT_WAKEUP | \
+ CSR_INT_BIT_ALIVE)
+
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */
+#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */
+#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */
+#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */
+#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */
+
+#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
+ CSR39_FH_INT_BIT_RX_CHNL2 | \
+ CSR_FH_INT_BIT_RX_CHNL1 | \
+ CSR_FH_INT_BIT_RX_CHNL0)
+
+
+#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \
+ CSR_FH_INT_BIT_TX_CHNL1 | \
+ CSR_FH_INT_BIT_TX_CHNL0)
+
+#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
+ CSR_FH_INT_BIT_RX_CHNL1 | \
+ CSR_FH_INT_BIT_RX_CHNL0)
+
+#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \
+ CSR_FH_INT_BIT_TX_CHNL0)
+
+
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD (0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK (0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
+
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE (0x400)
+/*
+ * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
+ * structures, error log, event log, verifying uCode load).
+ * First write to address register, then read from or write to data register
+ * to complete the job. Once the address register is set up, accesses to
+ * data registers auto-increment the address by one dword.
+ * Bit usage for address registers (read or write):
+ * 0-31: memory address within device
+ */
+#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c)
+#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010)
+#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
+#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)
+
+/*
+ * Registers for accessing device's internal peripheral registers
+ * (e.g. SCD, BSM, etc.). First write to address register,
+ * then read from or write to data register to complete the job.
+ * Bit usage for address registers (read or write):
+ * 0-15: register address (offset) within device
+ * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword)
+ */
+#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044)
+#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048)
+#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c)
+#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
+
+/*
+ * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
+ * Indicates index to next TFD that driver will fill (1 past latest filled).
+ * Bit usage:
+ * 0-7: queue write index
+ * 11-8: queue selector
+ */
+#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
+#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
+
+#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
+
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-4965-commands.h"
+#include "iwl-4965.h"
+#include "iwl-core.h"
+#include "iwl-4965-debug.h"
+#include "iwl-eeprom.h"
+#include "iwl-4965-io.h"
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+******************************************************************************/
+
+int iwlcore_eeprom_verify_signature(struct iwl4965_priv *priv)
+{
+ u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
+ if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ return -ENOENT;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
+
+/*
+ * The device's EEPROM semaphore prevents conflicts between driver and uCode
+ * when accessing the EEPROM; each access is a series of pulses to/from the
+ * EEPROM chip, not a single event, so even reads could conflict if they
+ * weren't arbitrated by the semaphore.
+ */
+int iwlcore_eeprom_acquire_semaphore(struct iwl4965_priv *priv)
+{
+ u16 count;
+ int ret;
+
+ for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+ /* Request semaphore */
+ iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+ /* See if we got it */
+ ret = iwl4965_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ EEPROM_SEM_TIMEOUT);
+ if (ret >= 0) {
+ IWL_DEBUG_IO("Acquired semaphore after %d tries.\n",
+ count+1);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(iwlcore_eeprom_acquire_semaphore);
+
+void iwlcore_eeprom_release_semaphore(struct iwl4965_priv *priv)
+{
+ iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+}
+EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore);
+
+
+/**
+ * iwl_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM contents from adapter into priv->eeprom
+ *
+ * NOTE: This routine uses the non-debug IO access functions.
+ */
+int iwl_eeprom_init(struct iwl4965_priv *priv)
+{
+ u16 *e = (u16 *)&priv->eeprom;
+ u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
+ u32 r;
+ int sz = sizeof(priv->eeprom);
+ int ret;
+ int i;
+ u16 addr;
+
+ /* The EEPROM structure has several padding buffers within it
+ * and when adding new EEPROM maps is subject to programmer errors
+ * which may be very difficult to identify without explicitly
+ * checking the resulting size of the eeprom map. */
+ BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+ if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ return -ENOENT;
+ }
+
+ /* Make sure driver (instead of uCode) is allowed to read EEPROM */
+ ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv);
+ if (ret < 0) {
+ IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
+ return -ENOENT;
+ }
+
+ /* eeprom is an array of 16bit values */
+ for (addr = 0; addr < sz; addr += sizeof(u16)) {
+ _iwl4965_write32(priv, CSR_EEPROM_REG, addr << 1);
+ _iwl4965_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+ for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+ i += IWL_EEPROM_ACCESS_DELAY) {
+ r = _iwl4965_read_direct32(priv, CSR_EEPROM_REG);
+ if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+ break;
+ udelay(IWL_EEPROM_ACCESS_DELAY);
+ }
+
+ if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+ IWL_ERROR("Time out reading EEPROM[%d]", addr);
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+ e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
+ }
+ ret = 0;
+
+done:
+ priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
+ return ret;
+}
+EXPORT_SYMBOL(iwl_eeprom_init);
+
+
+void iwl_eeprom_get_mac(const struct iwl4965_priv *priv, u8 *mac)
+{
+ memcpy(mac, priv->eeprom.mac_address, 6);
+}
+EXPORT_SYMBOL(iwl_eeprom_get_mac);
+
--- /dev/null
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_eeprom_h__
+#define __iwl_eeprom_h__
+
+struct iwl4965_priv;
+
+/*
+ * EEPROM access time values:
+ *
+ * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG,
+ * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit
+ * CSR_EEPROM_REG_BIT_CMD (0x2).
+ * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
+ * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
+ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
+ */
+#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */
+
+#define IWL_EEPROM_SEM_TIMEOUT 10 /* milliseconds */
+#define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
+
+
+/*
+ * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags.
+ *
+ * IBSS and/or AP operation is allowed *only* on those channels with
+ * (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because
+ * RADAR detection is not supported by the 4965 driver, but is a
+ * requirement for establishing a new network for legal operation on channels
+ * requiring RADAR detection or restricting ACTIVE scanning.
+ *
+ * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels.
+ * It only indicates that 20 MHz channel use is supported; FAT channel
+ * usage is indicated by a separate set of regulatory flags for each
+ * FAT channel pair.
+ *
+ * NOTE: Using a channel inappropriately will result in a uCode error!
+ */
+#define IWL_NUM_TX_CALIB_GROUPS 5
+enum {
+ EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */
+ EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */
+ /* Bit 2 Reserved */
+ EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */
+ EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */
+ EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */
+ EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */
+ EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */
+};
+
+/* SKU Capabilities */
+#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0)
+#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
+
+/* *regulatory* channel data format in eeprom, one for each channel.
+ * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */
+struct iwl4965_eeprom_channel {
+ u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */
+ s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
+} __attribute__ ((packed));
+
+/* 4965 has two radio transmitters (and 3 radio receivers) */
+#define EEPROM_TX_POWER_TX_CHAINS (2)
+
+/* 4965 has room for up to 8 sets of txpower calibration data */
+#define EEPROM_TX_POWER_BANDS (8)
+
+/* 4965 factory calibration measures txpower gain settings for
+ * each of 3 target output levels */
+#define EEPROM_TX_POWER_MEASUREMENTS (3)
+
+#define EEPROM_4965_TX_POWER_VERSION (2)
+
+/* 4965 driver does not work with txpower calibration version < 5.
+ * Look for this in calib_version member of struct iwl4965_eeprom. */
+#define EEPROM_TX_POWER_VERSION_NEW (5)
+
+
+/*
+ * 4965 factory calibration data for one txpower level, on one channel,
+ * measured on one of the 2 tx chains (radio transmitter and associated
+ * antenna). EEPROM contains:
+ *
+ * 1) Temperature (degrees Celsius) of device when measurement was made.
+ *
+ * 2) Gain table index used to achieve the target measurement power.
+ * This refers to the "well-known" gain tables (see iwl-4965-hw.h).
+ *
+ * 3) Actual measured output power, in half-dBm ("34" = 17 dBm).
+ *
+ * 4) RF power amplifier detector level measurement (not used).
+ */
+struct iwl4965_eeprom_calib_measure {
+ u8 temperature; /* Device temperature (Celsius) */
+ u8 gain_idx; /* Index into gain table */
+ u8 actual_pow; /* Measured RF output power, half-dBm */
+ s8 pa_det; /* Power amp detector level (not used) */
+} __attribute__ ((packed));
+
+
+/*
+ * 4965 measurement set for one channel. EEPROM contains:
+ *
+ * 1) Channel number measured
+ *
+ * 2) Measurements for each of 3 power levels for each of 2 radio transmitters
+ * (a.k.a. "tx chains") (6 measurements altogether)
+ */
+struct iwl4965_eeprom_calib_ch_info {
+ u8 ch_num;
+ struct iwl4965_eeprom_calib_measure
+ measurements[EEPROM_TX_POWER_TX_CHAINS]
+ [EEPROM_TX_POWER_MEASUREMENTS];
+} __attribute__ ((packed));
+
+/*
+ * 4965 txpower subband info.
+ *
+ * For each frequency subband, EEPROM contains the following:
+ *
+ * 1) First and last channels within range of the subband. "0" values
+ * indicate that this sample set is not being used.
+ *
+ * 2) Sample measurement sets for 2 channels close to the range endpoints.
+ */
+struct iwl4965_eeprom_calib_subband_info {
+ u8 ch_from; /* channel number of lowest channel in subband */
+ u8 ch_to; /* channel number of highest channel in subband */
+ struct iwl4965_eeprom_calib_ch_info ch1;
+ struct iwl4965_eeprom_calib_ch_info ch2;
+} __attribute__ ((packed));
+
+
+/*
+ * 4965 txpower calibration info. EEPROM contains:
+ *
+ * 1) Factory-measured saturation power levels (maximum levels at which
+ * tx power amplifier can output a signal without too much distortion).
+ * There is one level for 2.4 GHz band and one for 5 GHz band. These
+ * values apply to all channels within each of the bands.
+ *
+ * 2) Factory-measured power supply voltage level. This is assumed to be
+ * constant (i.e. same value applies to all channels/bands) while the
+ * factory measurements are being made.
+ *
+ * 3) Up to 8 sets of factory-measured txpower calibration values.
+ * These are for different frequency ranges, since txpower gain
+ * characteristics of the analog radio circuitry vary with frequency.
+ *
+ * Not all sets need to be filled with data;
+ * struct iwl4965_eeprom_calib_subband_info contains range of channels
+ * (0 if unused) for each set of data.
+ */
+struct iwl4965_eeprom_calib_info {
+ u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */
+ u8 saturation_power52; /* half-dBm */
+ s16 voltage; /* signed */
+ struct iwl4965_eeprom_calib_subband_info
+ band_info[EEPROM_TX_POWER_BANDS];
+} __attribute__ ((packed));
+
+
+
+/*
+ * 4965 EEPROM map
+ */
+struct iwl4965_eeprom {
+ u8 reserved0[16];
+#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */
+ u16 device_id; /* abs.ofs: 16 */
+ u8 reserved1[2];
+#define EEPROM_PMC (2*0x0A) /* 2 bytes */
+ u16 pmc; /* abs.ofs: 20 */
+ u8 reserved2[20];
+#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */
+ u8 mac_address[6]; /* abs.ofs: 42 */
+ u8 reserved3[58];
+#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */
+ u16 board_revision; /* abs.ofs: 106 */
+ u8 reserved4[11];
+#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
+ u8 board_pba_number[9]; /* abs.ofs: 119 */
+ u8 reserved5[8];
+#define EEPROM_VERSION (2*0x44) /* 2 bytes */
+ u16 version; /* abs.ofs: 136 */
+#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */
+ u8 sku_cap; /* abs.ofs: 138 */
+#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */
+ u8 leds_mode; /* abs.ofs: 139 */
+#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
+ u16 oem_mode;
+#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
+ u16 wowlan_mode; /* abs.ofs: 142 */
+#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */
+ u16 leds_time_interval; /* abs.ofs: 144 */
+#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */
+ u8 leds_off_time; /* abs.ofs: 146 */
+#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */
+ u8 leds_on_time; /* abs.ofs: 147 */
+#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */
+ u8 almgor_m_version; /* abs.ofs: 148 */
+#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */
+ u8 antenna_switch_type; /* abs.ofs: 149 */
+ u8 reserved6[8];
+#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */
+ u16 board_revision_4965; /* abs.ofs: 158 */
+ u8 reserved7[13];
+#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */
+ u8 board_pba_number_4965[9]; /* abs.ofs: 173 */
+ u8 reserved8[10];
+#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */
+ u8 sku_id[4]; /* abs.ofs: 192 */
+
+/*
+ * Per-channel regulatory data.
+ *
+ * Each channel that *might* be supported by 3945 or 4965 has a fixed location
+ * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
+ * txpower (MSB).
+ *
+ * Entries immediately below are for 20 MHz channel width. FAT (40 MHz)
+ * channels (only for 4965, not supported by 3945) appear later in the EEPROM.
+ *
+ * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+ */
+#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */
+ u16 band_1_count; /* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */
+ struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */
+
+/*
+ * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
+ * 5.0 GHz channels 7, 8, 11, 12, 16
+ * (4915-5080MHz) (none of these is ever supported)
+ */
+#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */
+ u16 band_2_count; /* abs.ofs: 226 */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */
+ struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */
+
+/*
+ * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+ * (5170-5320MHz)
+ */
+#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */
+ u16 band_3_count; /* abs.ofs: 254 */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */
+ struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */
+
+/*
+ * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+ * (5500-5700MHz)
+ */
+#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */
+ u16 band_4_count; /* abs.ofs: 280 */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */
+ struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */
+
+/*
+ * 5.7 GHz channels 145, 149, 153, 157, 161, 165
+ * (5725-5825MHz)
+ */
+#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */
+ u16 band_5_count; /* abs.ofs: 304 */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */
+ struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */
+
+ u8 reserved10[2];
+
+
+/*
+ * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
+ *
+ * The channel listed is the center of the lower 20 MHz half of the channel.
+ * The overall center frequency is actually 2 channels (10 MHz) above that,
+ * and the upper half of each FAT channel is centered 4 channels (20 MHz) away
+ * from the lower half; e.g. the upper half of FAT channel 1 is channel 5,
+ * and the overall FAT channel width centers on channel 3.
+ *
+ * NOTE: The RXON command uses 20 MHz channel numbers to specify the
+ * control channel to which to tune. RXON also specifies whether the
+ * control channel is the upper or lower half of a FAT channel.
+ *
+ * NOTE: 4965 does not support FAT channels on 2.4 GHz.
+ */
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */
+ struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */
+ u8 reserved11[2];
+
+/*
+ * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64),
+ * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
+ */
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */
+ struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */
+ u8 reserved12[6];
+
+/*
+ * 4965 driver requires txpower calibration format version 5 or greater.
+ * Driver does not work with txpower calibration version < 5.
+ * This value is simply a 16-bit number, no major/minor versions here.
+ */
+#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */
+ u16 calib_version; /* abs.ofs: 364 */
+ u8 reserved13[2];
+ u8 reserved14[96]; /* abs.ofs: 368 */
+
+/*
+ * 4965 Txpower calibration data.
+ */
+#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */
+ struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */
+
+ u8 reserved16[140]; /* fill out to full 1024 byte block */
+
+
+} __attribute__ ((packed));
+
+#define IWL_EEPROM_IMAGE_SIZE 1024
+
+/* End of EEPROM */
+
+struct iwl_eeprom_ops {
+ int (*verify_signature) (struct iwl4965_priv *priv);
+ int (*acquire_semaphore) (struct iwl4965_priv *priv);
+ void (*release_semaphore) (struct iwl4965_priv *priv);
+};
+
+
+void iwl_eeprom_get_mac(const struct iwl4965_priv *priv, u8 *mac);
+int iwl_eeprom_init(struct iwl4965_priv *priv);
+
+int iwlcore_eeprom_verify_signature(struct iwl4965_priv *priv);
+int iwlcore_eeprom_acquire_semaphore(struct iwl4965_priv *priv);
+void iwlcore_eeprom_release_semaphore(struct iwl4965_priv *priv);
+
+#endif /* __iwl_eeprom_h__ */
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
}
+/**
+ * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+ return ++index & (n_bd - 1);
+}
+
+/**
+ * iwl_queue_dec_wrap - decrement queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+ return --index & (n_bd - 1);
+}
+
/* TODO: Move fw_desc functions to iwl-pci.ko */
static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ieee80211 subsystem header files.
*
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
#include <asm/div64.h>
+#include "iwl-3945-core.h"
#include "iwl-3945.h"
#include "iwl-helpers.h"
#define VS
#endif
-#define IWLWIFI_VERSION "1.2.23k" VD VS
-#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation"
+#define IWLWIFI_VERSION "1.2.26k" VD VS
+#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation"
#define DRV_VERSION IWLWIFI_VERSION
-/* Change firmware file name, using "-" and incrementing number,
- * *only* when uCode interface or architecture changes so that it
- * is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL3945_UCODE_API "-1"
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
return NULL;
}
-static const struct ieee80211_hw_mode *iwl3945_get_hw_mode(
- struct iwl3945_priv *priv, int mode)
+static const struct ieee80211_supported_band *iwl3945_get_band(
+ struct iwl3945_priv *priv, enum ieee80211_band band)
{
- int i;
-
- for (i = 0; i < 3; i++)
- if (priv->modes[i].mode == mode)
- return &priv->modes[i];
-
- return NULL;
+ return priv->hw->wiphy->bands[band];
}
static int iwl3945_is_empty_essid(const char *essid, int essid_len)
return escaped;
}
-static void iwl3945_print_hex_dump(int level, void *p, u32 len)
-{
-#ifdef CONFIG_IWL3945_DEBUG
- if (!(iwl3945_debug_level & level))
- return;
-
- print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
- p, len, 1);
-#endif
-}
-
/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
* DMA services
*
* (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused.
***************************************************/
-static int iwl3945_queue_space(const struct iwl3945_queue *q)
+int iwl3945_queue_space(const struct iwl3945_queue *q)
{
int s = q->read_ptr - q->write_ptr;
return s;
}
-/**
- * iwl3945_queue_inc_wrap - increment queue index, wrap back to beginning
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl3945_queue_inc_wrap(int index, int n_bd)
-{
- return ++index & (n_bd - 1);
-}
-
-/**
- * iwl3945_queue_dec_wrap - increment queue index, wrap back to end
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl3945_queue_dec_wrap(int index, int n_bd)
-{
- return --index & (n_bd - 1);
-}
-
-static inline int x2_queue_used(const struct iwl3945_queue *q, int i)
+int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i)
{
return q->write_ptr > q->read_ptr ?
(i >= q->read_ptr && i < q->write_ptr) :
!(i < q->read_ptr && i >= q->write_ptr);
}
+
static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge)
{
/* This is for scan command, the big buffer at end of command array */
q->n_window = slots_num;
q->id = id;
- /* count must be power-of-two size, otherwise iwl3945_queue_inc_wrap
- * and iwl3945_queue_dec_wrap are broken. */
+ /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+ * and iwl_queue_dec_wrap are broken. */
BUG_ON(!is_power_of_2(count));
/* slots_num must be power-of-two size, otherwise
txq->need_update = 0;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
- * iwl3945_queue_inc_wrap and iwl3945_queue_dec_wrap are broken. */
+ * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
/* Initialize queue high/low-water, head/tail indexes */
/* first, empty all BD's */
for (; q->write_ptr != q->read_ptr;
- q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd))
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
iwl3945_hw_txq_free_tfd(priv, txq);
len = sizeof(struct iwl3945_cmd) * q->n_window;
station->sta.sta.sta_id = index;
station->sta.station_flags = 0;
- if (priv->phymode == MODE_IEEE80211A)
+ if (priv->band == IEEE80211_BAND_5GHZ)
rate = IWL_RATE_6M_PLCP;
else
rate = IWL_RATE_1M_PLCP;
txq->need_update = 1;
/* Increment and update queue's write index */
- q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd);
+ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
ret = iwl3945_tx_queue_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
/**
* iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON
- * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
- * @channel: Any channel valid for the requested phymode
+ * @band: 2.4 or 5 GHz band
+ * @channel: Any channel valid for the requested band
- * In addition to setting the staging RXON, priv->phymode is also set.
+ * In addition to setting the staging RXON, priv->band is also set.
*
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
- * in the staging RXON flag structure based on the phymode
+ * in the staging RXON flag structure based on the band
*/
-static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, u8 phymode, u16 channel)
+static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv,
+ enum ieee80211_band band,
+ u16 channel)
{
- if (!iwl3945_get_channel_info(priv, phymode, channel)) {
+ if (!iwl3945_get_channel_info(priv, band, channel)) {
IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
- channel, phymode);
+ channel, band);
return -EINVAL;
}
if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
- (priv->phymode == phymode))
+ (priv->band == band))
return 0;
priv->staging_rxon.channel = cpu_to_le16(channel);
- if (phymode == MODE_IEEE80211A)
+ if (band == IEEE80211_BAND_5GHZ)
priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
else
priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
- priv->phymode = phymode;
+ priv->band = band;
- IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+ IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band);
return 0;
}
return -EIO;
}
- /* Init the hardware's rate fallback order based on the
- * phymode */
+ /* Init the hardware's rate fallback order based on the band */
rc = iwl3945_init_hw_rate_table(priv);
if (rc) {
IWL_ERROR("Error setting HW rate table: %02X\n", rc);
return 0;
}
-/******************************************************************************
- *
- * Misc. internal state and helper functions
- *
- ******************************************************************************/
-#ifdef CONFIG_IWL3945_DEBUG
-
-/**
- * iwl3945_report_frame - dump frame to syslog during debug sessions
- *
- * You may hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good frames.
- */
-void iwl3945_report_frame(struct iwl3945_priv *priv,
- struct iwl3945_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100)
-{
- u32 to_us;
- u32 print_summary = 0;
- u32 print_dump = 0; /* set to 1 to dump all frames' contents */
- u32 hundred = 0;
- u32 dataframe = 0;
- u16 fc;
- u16 seq_ctl;
- u16 channel;
- u16 phy_flags;
- int rate_sym;
- u16 length;
- u16 status;
- u16 bcn_tmr;
- u32 tsf_low;
- u64 tsf;
- u8 rssi;
- u8 agc;
- u16 sig_avg;
- u16 noise_diff;
- struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
- struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
- struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
- u8 *data = IWL_RX_DATA(pkt);
-
- /* MAC header */
- fc = le16_to_cpu(header->frame_control);
- seq_ctl = le16_to_cpu(header->seq_ctrl);
-
- /* metadata */
- channel = le16_to_cpu(rx_hdr->channel);
- phy_flags = le16_to_cpu(rx_hdr->phy_flags);
- rate_sym = rx_hdr->rate;
- length = le16_to_cpu(rx_hdr->len);
-
- /* end-of-frame status and timestamp */
- status = le32_to_cpu(rx_end->status);
- bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
- tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
- tsf = le64_to_cpu(rx_end->timestamp);
-
- /* signal statistics */
- rssi = rx_stats->rssi;
- agc = rx_stats->agc;
- sig_avg = le16_to_cpu(rx_stats->sig_avg);
- noise_diff = le16_to_cpu(rx_stats->noise_diff);
-
- to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
- /* if data frame is to us and all is good,
- * (optionally) print summary for only 1 out of every 100 */
- if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
- (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
- dataframe = 1;
- if (!group100)
- print_summary = 1; /* print each frame */
- else if (priv->framecnt_to_us < 100) {
- priv->framecnt_to_us++;
- print_summary = 0;
- } else {
- priv->framecnt_to_us = 0;
- print_summary = 1;
- hundred = 1;
- }
- } else {
- /* print summary for all other frames */
- print_summary = 1;
- }
-
- if (print_summary) {
- char *title;
- u32 rate;
-
- if (hundred)
- title = "100Frames";
- else if (fc & IEEE80211_FCTL_RETRY)
- title = "Retry";
- else if (ieee80211_is_assoc_response(fc))
- title = "AscRsp";
- else if (ieee80211_is_reassoc_response(fc))
- title = "RasRsp";
- else if (ieee80211_is_probe_response(fc)) {
- title = "PrbRsp";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_beacon(fc)) {
- title = "Beacon";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_atim(fc))
- title = "ATIM";
- else if (ieee80211_is_auth(fc))
- title = "Auth";
- else if (ieee80211_is_deauth(fc))
- title = "DeAuth";
- else if (ieee80211_is_disassoc(fc))
- title = "DisAssoc";
- else
- title = "Frame";
-
- rate = iwl3945_rate_index_from_plcp(rate_sym);
- if (rate == -1)
- rate = 0;
- else
- rate = iwl3945_rates[rate].ieee / 2;
-
- /* print frame summary.
- * MAC addresses show just the last byte (for brevity),
- * but you can hack it to show more, if you'd like to. */
- if (dataframe)
- IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
- "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
- title, fc, header->addr1[5],
- length, rssi, channel, rate);
- else {
- /* src/dst addresses assume managed mode */
- IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
- "src=0x%02x, rssi=%u, tim=%lu usec, "
- "phy=0x%02x, chnl=%d\n",
- title, fc, header->addr1[5],
- header->addr3[5], rssi,
- tsf_low - priv->scan_start_tsf,
- phy_flags, channel);
- }
- }
- if (print_dump)
- iwl3945_print_hex_dump(IWL_DL_RX, data, length);
-}
-#endif
-
static void iwl3945_unset_hw_setting(struct iwl3945_priv *priv)
{
if (priv->hw_setting.shared_virt)
/*
* QoS support
*/
-#ifdef CONFIG_IWL3945_QOS
static int iwl3945_send_qos_params_command(struct iwl3945_priv *priv,
struct iwl3945_qosparam_cmd *qos)
{
}
}
-#endif /* CONFIG_IWL3945_QOS */
/*
* Power management (not Tx power!) functions
*/
return 1;
}
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
-
-static const char *iwl3945_get_tx_fail_reason(u32 status)
-{
- switch (status & TX_STATUS_MSK) {
- case TX_STATUS_SUCCESS:
- return "SUCCESS";
- TX_STATUS_ENTRY(SHORT_LIMIT);
- TX_STATUS_ENTRY(LONG_LIMIT);
- TX_STATUS_ENTRY(FIFO_UNDERRUN);
- TX_STATUS_ENTRY(MGMNT_ABORT);
- TX_STATUS_ENTRY(NEXT_FRAG);
- TX_STATUS_ENTRY(LIFE_EXPIRE);
- TX_STATUS_ENTRY(DEST_PS);
- TX_STATUS_ENTRY(ABORTED);
- TX_STATUS_ENTRY(BT_RETRY);
- TX_STATUS_ENTRY(STA_INVALID);
- TX_STATUS_ENTRY(FRAG_DROPPED);
- TX_STATUS_ENTRY(TID_DISABLE);
- TX_STATUS_ENTRY(FRAME_FLUSHED);
- TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
- TX_STATUS_ENTRY(TX_LOCKED);
- TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
- }
-
- return "UNKNOWN";
-}
-
/**
* iwl3945_scan_cancel - Cancel any currently executing HW scan
*
return 0;
}
-static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode)
+static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv,
+ enum ieee80211_band band)
{
- if (phymode == MODE_IEEE80211A) {
+ if (band == IEEE80211_BAND_5GHZ) {
priv->staging_rxon.flags &=
~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
| RXON_FLG_CCK_MSK);
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
#endif
- ch_info = iwl3945_get_channel_info(priv, priv->phymode,
+ ch_info = iwl3945_get_channel_info(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel));
if (!ch_info)
priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
if (is_channel_a_band(ch_info))
- priv->phymode = MODE_IEEE80211A;
+ priv->band = IEEE80211_BAND_5GHZ;
else
- priv->phymode = MODE_IEEE80211G;
+ priv->band = IEEE80211_BAND_2GHZ;
- iwl3945_set_flags_for_phymode(priv, priv->phymode);
+ iwl3945_set_flags_for_phymode(priv, priv->band);
priv->staging_rxon.ofdm_basic_rates =
(IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
const struct iwl3945_channel_info *ch_info;
ch_info = iwl3945_get_channel_info(priv,
- priv->phymode,
+ priv->band,
le16_to_cpu(priv->staging_rxon.channel));
if (!ch_info || !is_channel_ibss(ch_info)) {
goto drop_unlock;
}
- if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+ if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) {
IWL_ERROR("ERROR: No TX rate available.\n");
goto drop_unlock;
}
ieee80211_get_hdrlen(fc));
/* Tell device the write index *just past* this latest filled TFD */
- q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd);
+ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
rc = iwl3945_tx_queue_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
static void iwl3945_set_rate(struct iwl3945_priv *priv)
{
- const struct ieee80211_hw_mode *hw = NULL;
+ const struct ieee80211_supported_band *sband = NULL;
struct ieee80211_rate *rate;
int i;
- hw = iwl3945_get_hw_mode(priv, priv->phymode);
- if (!hw) {
+ sband = iwl3945_get_band(priv, priv->band);
+ if (!sband) {
IWL_ERROR("Failed to set rate: unable to get hw mode\n");
return;
}
priv->active_rate = 0;
priv->active_rate_basic = 0;
- IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
- hw->mode == MODE_IEEE80211A ?
- 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
-
- for (i = 0; i < hw->num_rates; i++) {
- rate = &(hw->rates[i]);
- if ((rate->val < IWL_RATE_COUNT) &&
- (rate->flags & IEEE80211_RATE_SUPPORTED)) {
- IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
- rate->val, iwl3945_rates[rate->val].plcp,
- (rate->flags & IEEE80211_RATE_BASIC) ?
- "*" : "");
- priv->active_rate |= (1 << rate->val);
- if (rate->flags & IEEE80211_RATE_BASIC)
- priv->active_rate_basic |= (1 << rate->val);
- } else
- IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
- rate->val, iwl3945_rates[rate->val].plcp);
+ IWL_DEBUG_RATE("Setting rates for %s GHz\n",
+ sband->band == IEEE80211_BAND_2GHZ ? "2.4" : "5");
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ rate = &sband->bitrates[i];
+ if ((rate->hw_value < IWL_RATE_COUNT) &&
+ !(rate->flags & IEEE80211_CHAN_DISABLED)) {
+ IWL_DEBUG_RATE("Adding rate index %d (plcp %d)\n",
+ rate->hw_value, iwl3945_rates[rate->hw_value].plcp);
+ priv->active_rate |= (1 << rate->hw_value);
+ }
}
IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
}
#endif
-static void iwl3945_txstatus_to_ieee(struct iwl3945_priv *priv,
- struct iwl3945_tx_info *tx_sta)
-{
-
- tx_sta->status.ack_signal = 0;
- tx_sta->status.excessive_retries = 0;
- tx_sta->status.queue_length = 0;
- tx_sta->status.queue_number = 0;
-
- if (in_interrupt())
- ieee80211_tx_status_irqsafe(priv->hw,
- tx_sta->skb[0], &(tx_sta->status));
- else
- ieee80211_tx_status(priv->hw,
- tx_sta->skb[0], &(tx_sta->status));
-
- tx_sta->skb[0] = NULL;
-}
-
-/**
- * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
- *
- * When FW advances 'R' index, all entries between old and new 'R' index
- * need to be reclaimed. As result, some free space forms. If there is
- * enough free space (> low mark), wake the stack that feeds us.
- */
-static int iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, int txq_id, int index)
-{
- struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
- struct iwl3945_queue *q = &txq->q;
- int nfreed = 0;
-
- if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
- IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
- "is out of range [0-%d] %d %d.\n", txq_id,
- index, q->n_bd, q->write_ptr, q->read_ptr);
- return 0;
- }
-
- for (index = iwl3945_queue_inc_wrap(index, q->n_bd);
- q->read_ptr != index;
- q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) {
- if (txq_id != IWL_CMD_QUEUE_NUM) {
- iwl3945_txstatus_to_ieee(priv,
- &(txq->txb[txq->q.read_ptr]));
- iwl3945_hw_txq_free_tfd(priv, txq);
- } else if (nfreed > 1) {
- IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
- q->write_ptr, q->read_ptr);
- queue_work(priv->workqueue, &priv->restart);
- }
- nfreed++;
- }
-
- if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) &&
- (txq_id != IWL_CMD_QUEUE_NUM) &&
- priv->mac80211_registered)
- ieee80211_wake_queue(priv->hw, txq_id);
-
-
- return nfreed;
-}
-
-static int iwl3945_is_tx_success(u32 status)
-{
- return (status & 0xFF) == 0x1;
-}
-
-/******************************************************************************
- *
- * Generic RX handler implementations
- *
- ******************************************************************************/
-/**
- * iwl3945_rx_reply_tx - Handle Tx response
- */
-static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
- struct iwl3945_rx_mem_buffer *rxb)
-{
- struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
- u16 sequence = le16_to_cpu(pkt->hdr.sequence);
- int txq_id = SEQ_TO_QUEUE(sequence);
- int index = SEQ_TO_INDEX(sequence);
- struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
- struct ieee80211_tx_status *tx_status;
- struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
- u32 status = le32_to_cpu(tx_resp->status);
-
- if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
- IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
- "is out of range [0-%d] %d %d\n", txq_id,
- index, txq->q.n_bd, txq->q.write_ptr,
- txq->q.read_ptr);
- return;
- }
-
- tx_status = &(txq->txb[txq->q.read_ptr].status);
-
- tx_status->retry_count = tx_resp->failure_frame;
- tx_status->queue_number = status;
- tx_status->queue_length = tx_resp->bt_kill_count;
- tx_status->queue_length |= tx_resp->failure_rts;
-
- tx_status->flags =
- iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
-
- tx_status->control.tx_rate = iwl3945_rate_index_from_plcp(tx_resp->rate);
-
- IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
- txq_id, iwl3945_get_tx_fail_reason(status), status,
- tx_resp->rate, tx_resp->failure_frame);
-
- IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
- if (index != -1)
- iwl3945_tx_queue_reclaim(priv, txq_id, index);
-
- if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
- IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
-}
-
-
static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv,
struct iwl3945_rx_mem_buffer *rxb)
{
priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
iwl3945_rx_scan_complete_notif;
priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif;
- priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx;
/* Set up hardware specific Rx handlers */
iwl3945_hw_rx_handler_setup(priv);
}
/**
+ * iwl3945_cmd_queue_reclaim - Reclaim CMD queue entries
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed.
+ */
+static void iwl3945_cmd_queue_reclaim(struct iwl3945_priv *priv,
+ int txq_id, int index)
+{
+ struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl3945_queue *q = &txq->q;
+ int nfreed = 0;
+
+ if ((index >= q->n_bd) || (iwl3945_x2_queue_used(q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+ "is out of range [0-%d] %d %d.\n", txq_id,
+ index, q->n_bd, q->write_ptr, q->read_ptr);
+ return;
+ }
+
+ for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+ if (nfreed > 1) {
+ IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+ q->write_ptr, q->read_ptr);
+ queue_work(priv->workqueue, &priv->restart);
+ break;
+ }
+ nfreed++;
+ }
+}
+
+
+/**
* iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
* @rxb: Rx buffer to reclaim
*
int cmd_index;
struct iwl3945_cmd *cmd;
- /* If a Tx command is being handled and it isn't in the actual
- * command queue then there a command routing bug has been introduced
- * in the queue management code. */
- if (txq_id != IWL_CMD_QUEUE_NUM)
- IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
- txq_id, pkt->hdr.cmd);
BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
!cmd->meta.u.callback(priv, cmd, rxb->skb))
rxb->skb = NULL;
- iwl3945_tx_queue_reclaim(priv, txq_id, index);
+ iwl3945_cmd_queue_reclaim(priv, txq_id, index);
if (!(cmd->meta.flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
IWL_ERROR("Start IWL Error Log Dump:\n");
- IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
- priv->status, priv->config, count);
+ IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count);
}
IWL_ERROR("Desc Time asrtPC blink2 "
* atomic, make sure that inta covers all the interrupts that
* we've discovered, even if FH interrupt came in just after
* reading CSR_INT. */
- if (inta_fh & CSR_FH_INT_RX_MASK)
+ if (inta_fh & CSR39_FH_INT_RX_MASK)
inta |= CSR_INT_BIT_FH_RX;
- if (inta_fh & CSR_FH_INT_TX_MASK)
+ if (inta_fh & CSR39_FH_INT_TX_MASK)
inta |= CSR_INT_BIT_FH_TX;
/* Now service all interrupt bits discovered above. */
/* Queue restart only if RF_KILL switch was set to "kill"
* when we loaded driver, and is now set to "enable".
* After we're Alive, RF_KILL gets handled by
- * iwl_rx_card_state_notif() */
+ * iwl3945_rx_card_state_notif() */
if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
clear_bit(STATUS_RF_KILL_HW, &priv->status);
queue_work(priv->workqueue, &priv->restart);
* Based on band and channel number.
*/
const struct iwl3945_channel_info *iwl3945_get_channel_info(const struct iwl3945_priv *priv,
- int phymode, u16 channel)
+ enum ieee80211_band band, u16 channel)
{
int i;
- switch (phymode) {
- case MODE_IEEE80211A:
+ switch (band) {
+ case IEEE80211_BAND_5GHZ:
for (i = 14; i < priv->channel_count; i++) {
if (priv->channel_info[i].channel == channel)
return &priv->channel_info[i];
}
break;
- case MODE_IEEE80211B:
- case MODE_IEEE80211G:
+ case IEEE80211_BAND_2GHZ:
if (channel >= 1 && channel <= 14)
return &priv->channel_info[channel - 1];
break;
-
+ case IEEE80211_NUM_BANDS:
+ WARN_ON(1);
}
return NULL;
/* Loop through each band adding each of the channels */
for (ch = 0; ch < eeprom_ch_count; ch++) {
ch_info->channel = eeprom_ch_index[ch];
- ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
- MODE_IEEE80211A;
+ ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ;
/* permanently store EEPROM's channel regulatory flags
* and max power in channel info database. */
ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
ch_info->min_power = 0;
- IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+ IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x"
" %ddBm): Ad-Hoc %ssupported\n",
ch_info->channel,
is_channel_a_band(ch_info) ?
"5.2" : "2.4",
+ CHECK_AND_PRINT(VALID),
CHECK_AND_PRINT(IBSS),
CHECK_AND_PRINT(ACTIVE),
CHECK_AND_PRINT(RADAR),
#define IWL_PASSIVE_DWELL_BASE (100)
#define IWL_CHANNEL_TUNE_TIME 5
-static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, int phymode)
+static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv,
+ enum ieee80211_band band)
{
- if (phymode == MODE_IEEE80211A)
+ if (band == IEEE80211_BAND_5GHZ)
return IWL_ACTIVE_DWELL_TIME_52;
else
return IWL_ACTIVE_DWELL_TIME_24;
}
-static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode)
+static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv,
+ enum ieee80211_band band)
{
- u16 active = iwl3945_get_active_dwell_time(priv, phymode);
- u16 passive = (phymode != MODE_IEEE80211A) ?
+ u16 active = iwl3945_get_active_dwell_time(priv, band);
+ u16 passive = (band == IEEE80211_BAND_2GHZ) ?
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
return passive;
}
-static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode,
+static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
+ enum ieee80211_band band,
u8 is_active, u8 direct_mask,
struct iwl3945_scan_channel *scan_ch)
{
const struct ieee80211_channel *channels = NULL;
- const struct ieee80211_hw_mode *hw_mode;
+ const struct ieee80211_supported_band *sband;
const struct iwl3945_channel_info *ch_info;
u16 passive_dwell = 0;
u16 active_dwell = 0;
int added, i;
- hw_mode = iwl3945_get_hw_mode(priv, phymode);
- if (!hw_mode)
+ sband = iwl3945_get_band(priv, band);
+ if (!sband)
return 0;
- channels = hw_mode->channels;
+ channels = sband->channels;
- active_dwell = iwl3945_get_active_dwell_time(priv, phymode);
- passive_dwell = iwl3945_get_passive_dwell_time(priv, phymode);
+ active_dwell = iwl3945_get_active_dwell_time(priv, band);
+ passive_dwell = iwl3945_get_passive_dwell_time(priv, band);
- for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
- if (channels[i].chan ==
+ for (i = 0, added = 0; i < sband->n_channels; i++) {
+ if (channels[i].hw_value ==
le16_to_cpu(priv->active_rxon.channel)) {
if (iwl3945_is_associated(priv)) {
IWL_DEBUG_SCAN
} else if (priv->only_active_channel)
continue;
- scan_ch->channel = channels[i].chan;
+ scan_ch->channel = channels[i].hw_value;
- ch_info = iwl3945_get_channel_info(priv, phymode, scan_ch->channel);
+ ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel);
if (!is_channel_valid(ch_info)) {
IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
scan_ch->channel);
}
if (!is_active || is_channel_passive(ch_info) ||
- !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+ (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
scan_ch->type = 0; /* passive */
else
scan_ch->type = 1; /* active */
/* scan_pwr_info->tpc.dsp_atten; */
/*scan_pwr_info->tpc.tx_gain; */
- if (phymode == MODE_IEEE80211A)
+ if (band == IEEE80211_BAND_5GHZ)
scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
else {
scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
return added;
}
-static void iwl3945_reset_channel_flag(struct iwl3945_priv *priv)
-{
- int i, j;
- for (i = 0; i < 3; i++) {
- struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
- for (j = 0; j < hw_mode->num_channels; j++)
- hw_mode->channels[j].flag = hw_mode->channels[j].val;
- }
-}
-
static void iwl3945_init_hw_rates(struct iwl3945_priv *priv,
struct ieee80211_rate *rates)
{
int i;
for (i = 0; i < IWL_RATE_COUNT; i++) {
- rates[i].rate = iwl3945_rates[i].ieee * 5;
- rates[i].val = i; /* Rate scaling will work on indexes */
- rates[i].val2 = i;
- rates[i].flags = IEEE80211_RATE_SUPPORTED;
- /* Only OFDM have the bits-per-symbol set */
- if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
- rates[i].flags |= IEEE80211_RATE_OFDM;
- else {
+ rates[i].bitrate = iwl3945_rates[i].ieee * 5;
+ rates[i].hw_value = i; /* Rate scaling will work on indexes */
+ rates[i].hw_value_short = i;
+ rates[i].flags = 0;
+ if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
/*
- * If CCK 1M then set rate flag to CCK else CCK_2
- * which is CCK | PREAMBLE2
+ * If CCK != 1M then set short preamble rate flag.
*/
rates[i].flags |= (iwl3945_rates[i].plcp == 10) ?
- IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+ 0 : IEEE80211_RATE_SHORT_PREAMBLE;
}
-
- /* Set up which ones are basic rates... */
- if (IWL_BASIC_RATES_MASK & (1 << i))
- rates[i].flags |= IEEE80211_RATE_BASIC;
}
}
static int iwl3945_init_geos(struct iwl3945_priv *priv)
{
struct iwl3945_channel_info *ch;
- struct ieee80211_hw_mode *modes;
+ struct ieee80211_supported_band *sband;
struct ieee80211_channel *channels;
struct ieee80211_channel *geo_ch;
struct ieee80211_rate *rates;
int i = 0;
- enum {
- A = 0,
- B = 1,
- G = 2,
- };
- int mode_count = 3;
- if (priv->modes) {
+ if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
+ priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
IWL_DEBUG_INFO("Geography modes already initialized.\n");
set_bit(STATUS_GEO_CONFIGURED, &priv->status);
return 0;
}
- modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
- GFP_KERNEL);
- if (!modes)
- return -ENOMEM;
-
channels = kzalloc(sizeof(struct ieee80211_channel) *
priv->channel_count, GFP_KERNEL);
- if (!channels) {
- kfree(modes);
+ if (!channels)
return -ENOMEM;
- }
- rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+ rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
GFP_KERNEL);
if (!rates) {
- kfree(modes);
kfree(channels);
return -ENOMEM;
}
- /* 0 = 802.11a
- * 1 = 802.11b
- * 2 = 802.11g
- */
-
/* 5.2GHz channels start after the 2.4GHz channels */
- modes[A].mode = MODE_IEEE80211A;
- modes[A].channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)];
- modes[A].rates = &rates[4];
- modes[A].num_rates = 8; /* just OFDM */
- modes[A].num_channels = 0;
-
- modes[B].mode = MODE_IEEE80211B;
- modes[B].channels = channels;
- modes[B].rates = rates;
- modes[B].num_rates = 4; /* just CCK */
- modes[B].num_channels = 0;
-
- modes[G].mode = MODE_IEEE80211G;
- modes[G].channels = channels;
- modes[G].rates = rates;
- modes[G].num_rates = 12; /* OFDM & CCK */
- modes[G].num_channels = 0;
+ sband = &priv->bands[IEEE80211_BAND_5GHZ];
+ sband->channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)];
+ /* just OFDM */
+ sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
+ sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
+
+ sband = &priv->bands[IEEE80211_BAND_2GHZ];
+ sband->channels = channels;
+ /* OFDM & CCK */
+ sband->bitrates = rates;
+ sband->n_bitrates = IWL_RATE_COUNT;
priv->ieee_channels = channels;
priv->ieee_rates = rates;
iwl3945_init_hw_rates(priv, rates);
- for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+ for (i = 0; i < priv->channel_count; i++) {
ch = &priv->channel_info[i];
- if (!is_channel_valid(ch)) {
- IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
- "skipping.\n",
- ch->channel, is_channel_a_band(ch) ?
- "5.2" : "2.4");
+ /* FIXME: might be removed if scan is OK*/
+ if (!is_channel_valid(ch))
continue;
- }
if (is_channel_a_band(ch))
- geo_ch = &modes[A].channels[modes[A].num_channels++];
- else {
- geo_ch = &modes[B].channels[modes[B].num_channels++];
- modes[G].num_channels++;
- }
+ sband = &priv->bands[IEEE80211_BAND_5GHZ];
+ else
+ sband = &priv->bands[IEEE80211_BAND_2GHZ];
- geo_ch->freq = ieee80211chan2mhz(ch->channel);
- geo_ch->chan = ch->channel;
- geo_ch->power_level = ch->max_power_avg;
- geo_ch->antenna_max = 0xff;
+ geo_ch = &sband->channels[sband->n_channels++];
+
+ geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel);
+ geo_ch->max_power = ch->max_power_avg;
+ geo_ch->max_antenna_gain = 0xff;
+ geo_ch->hw_value = ch->channel;
if (is_channel_valid(ch)) {
- geo_ch->flag = IEEE80211_CHAN_W_SCAN;
- if (ch->flags & EEPROM_CHANNEL_IBSS)
- geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+ if (!(ch->flags & EEPROM_CHANNEL_IBSS))
+ geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
- if (ch->flags & EEPROM_CHANNEL_ACTIVE)
- geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+ if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
+ geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
if (ch->flags & EEPROM_CHANNEL_RADAR)
- geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+ geo_ch->flags |= IEEE80211_CHAN_RADAR;
if (ch->max_power_avg > priv->max_channel_txpower_limit)
priv->max_channel_txpower_limit =
ch->max_power_avg;
+ } else {
+ geo_ch->flags |= IEEE80211_CHAN_DISABLED;
}
- geo_ch->val = geo_ch->flag;
+ /* Save flags for reg domain usage */
+ geo_ch->orig_flags = geo_ch->flags;
+
+ IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n",
+ ch->channel, geo_ch->center_freq,
+ is_channel_a_band(ch) ? "5.2" : "2.4",
+ geo_ch->flags & IEEE80211_CHAN_DISABLED ?
+ "restricted" : "valid",
+ geo_ch->flags);
}
- if ((modes[A].num_channels == 0) && priv->is_abg) {
+ if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
+ priv->cfg->sku & IWL_SKU_A) {
printk(KERN_INFO DRV_NAME
": Incorrectly detected BG card as ABG. Please send "
"your PCI ID 0x%04X:0x%04X to maintainer.\n",
priv->pci_dev->device, priv->pci_dev->subsystem_device);
- priv->is_abg = 0;
+ priv->cfg->sku &= ~IWL_SKU_A;
}
printk(KERN_INFO DRV_NAME
": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
- modes[G].num_channels, modes[A].num_channels);
-
- /*
- * NOTE: We register these in preference of order -- the
- * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
- * a phymode based on rates or AP capabilities but seems to
- * configure it purely on if the channel being configured
- * is supported by a mode -- and the first match is taken
- */
+ priv->bands[IEEE80211_BAND_2GHZ].n_channels,
+ priv->bands[IEEE80211_BAND_5GHZ].n_channels);
- if (modes[G].num_channels)
- ieee80211_register_hwmode(priv->hw, &modes[G]);
- if (modes[B].num_channels)
- ieee80211_register_hwmode(priv->hw, &modes[B]);
- if (modes[A].num_channels)
- ieee80211_register_hwmode(priv->hw, &modes[A]);
+ priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->bands[IEEE80211_BAND_2GHZ];
+ priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ];
- priv->modes = modes;
set_bit(STATUS_GEO_CONFIGURED, &priv->status);
return 0;
*/
static void iwl3945_free_geos(struct iwl3945_priv *priv)
{
- kfree(priv->modes);
kfree(priv->ieee_channels);
kfree(priv->ieee_rates);
clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
int ret = 0;
const struct firmware *ucode_raw;
/* firmware file name contains uCode/driver compatibility version */
- const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode";
+ const char *name = priv->cfg->fw_name;
u8 *src;
size_t len;
u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
struct iwl3945_scan_cmd *scan;
struct ieee80211_conf *conf = NULL;
u8 direct_mask;
- int phymode;
+ enum ieee80211_band band;
conf = ieee80211_get_hw_conf(priv->hw);
scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
scan->good_CRC_th = 0;
- phymode = MODE_IEEE80211G;
+ band = IEEE80211_BAND_2GHZ;
break;
case 1:
scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
scan->good_CRC_th = IWL_GOOD_CRC_TH;
- phymode = MODE_IEEE80211A;
+ band = IEEE80211_BAND_5GHZ;
break;
default:
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
- if (direct_mask)
+ if (direct_mask) {
IWL_DEBUG_SCAN
("Initiating direct scan for %s.\n",
iwl3945_escape_essid(priv->essid, priv->essid_len));
- else
+ scan->channel_count =
+ iwl3945_get_channels_for_scan(
+ priv, band, 1, /* active */
+ direct_mask,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+ } else {
IWL_DEBUG_SCAN("Initiating indirect scan.\n");
-
- scan->channel_count =
- iwl3945_get_channels_for_scan(
- priv, phymode, 1, /* active */
- direct_mask,
- (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+ scan->channel_count =
+ iwl3945_get_channels_for_scan(
+ priv, band, 0, /* passive */
+ direct_mask,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+ }
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
scan->channel_count * sizeof(struct iwl3945_scan_channel);
iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
iwl3945_add_station(priv, priv->bssid, 0, 0);
iwl3945_sync_sta(priv, IWL_STA_ID,
- (priv->phymode == MODE_IEEE80211A)?
+ (priv->band == IEEE80211_BAND_5GHZ) ?
IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
CMD_ASYNC);
iwl3945_rate_scale_init(priv->hw, IWL_STA_ID);
iwl3945_sequence_reset(priv);
-#ifdef CONFIG_IWL3945_QOS
iwl3945_activate_qos(priv, 0);
-#endif /* CONFIG_IWL3945_QOS */
+
/* we have just associated, don't start scan too early */
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
mutex_unlock(&priv->mutex);
}
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
- ctl->tx_rate);
+ ctl->tx_rate->bitrate);
if (iwl3945_tx_skb(priv, skb, ctl))
dev_kfree_skb_any(skb);
int ret = 0;
mutex_lock(&priv->mutex);
- IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+ IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
spin_lock_irqsave(&priv->lock, flags);
- ch_info = iwl3945_get_channel_info(priv, conf->phymode, conf->channel);
+ ch_info = iwl3945_get_channel_info(priv, conf->channel->band,
+ conf->channel->hw_value);
if (!is_channel_valid(ch_info)) {
IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
- conf->channel, conf->phymode);
+ conf->channel->hw_value, conf->channel->band);
IWL_DEBUG_MAC80211("leave - invalid channel\n");
spin_unlock_irqrestore(&priv->lock, flags);
ret = -EINVAL;
goto out;
}
- iwl3945_set_rxon_channel(priv, conf->phymode, conf->channel);
+ iwl3945_set_rxon_channel(priv, conf->channel->band, conf->channel->hw_value);
- iwl3945_set_flags_for_phymode(priv, conf->phymode);
+ iwl3945_set_flags_for_phymode(priv, conf->channel->band);
/* The list of supported rates and rate mask can be different
* for each phymode; since the phymode may have changed, reset
if (conf == NULL)
return -EIO;
+ if (priv->vif != vif) {
+ IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
/* XXX: this MUST use conf->mac_addr */
if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
!(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
*/
- if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
- IWL_DEBUG_MAC80211("leave - scanning\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- if (priv->vif != vif) {
- IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
if (!conf->bssid) {
const struct ieee80211_tx_queue_params *params)
{
struct iwl3945_priv *priv = hw->priv;
-#ifdef CONFIG_IWL3945_QOS
unsigned long flags;
int q;
-#endif /* CONFIG_IWL3945_QOS */
IWL_DEBUG_MAC80211("enter\n");
return 0;
}
-#ifdef CONFIG_IWL3945_QOS
if (!priv->qos_data.qos_enable) {
priv->qos_data.qos_active = 0;
IWL_DEBUG_MAC80211("leave - qos not enabled\n");
priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
priv->qos_data.def_qos_parm.ac[q].edca_txop =
- cpu_to_le16((params->burst_time * 100));
+ cpu_to_le16((params->txop * 32));
priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
priv->qos_data.qos_active = 1;
mutex_unlock(&priv->mutex);
-#endif /*CONFIG_IWL3945_QOS */
-
IWL_DEBUG_MAC80211("leave\n");
return 0;
}
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211("enter\n");
-#ifdef CONFIG_IWL3945_QOS
iwl3945_reset_qos(priv);
-#endif
+
cancel_delayed_work(&priv->post_associate);
spin_lock_irqsave(&priv->lock, flags);
IWL_DEBUG_MAC80211("leave\n");
spin_unlock_irqrestore(&priv->lock, flags);
-#ifdef CONFIG_IWL3945_QOS
iwl3945_reset_qos(priv);
-#endif
queue_work(priv->workqueue, &priv->post_associate.work);
static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
store_filter_flags);
-static ssize_t show_tune(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
-
- return sprintf(buf, "0x%04X\n",
- (priv->phymode << 8) |
- le16_to_cpu(priv->active_rxon.channel));
-}
-
-static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode);
-
-static ssize_t store_tune(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
- char *p = (char *)buf;
- u16 tune = simple_strtoul(p, &p, 0);
- u8 phymode = (tune >> 8) & 0xff;
- u16 channel = tune & 0xff;
-
- IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
-
- mutex_lock(&priv->mutex);
- if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
- (priv->phymode != phymode)) {
- const struct iwl3945_channel_info *ch_info;
-
- ch_info = iwl3945_get_channel_info(priv, phymode, channel);
- if (!ch_info) {
- IWL_WARNING("Requested invalid phymode/channel "
- "combination: %d %d\n", phymode, channel);
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- /* Cancel any currently running scans... */
- if (iwl3945_scan_cancel_timeout(priv, 100))
- IWL_WARNING("Could not cancel scan.\n");
- else {
- IWL_DEBUG_INFO("Committing phymode and "
- "rxon.channel = %d %d\n",
- phymode, channel);
-
- iwl3945_set_rxon_channel(priv, phymode, channel);
- iwl3945_set_flags_for_phymode(priv, phymode);
-
- iwl3945_set_rate(priv);
- iwl3945_commit_rxon(priv);
- }
- }
- mutex_unlock(&priv->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
-
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
static ssize_t show_measurement(struct device *d,
show_measurement, store_measurement);
#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */
-static ssize_t show_rate(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl3945_priv *priv = dev_get_drvdata(d);
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
- i = priv->stations[IWL_AP_ID].current_rate.s.rate;
- else
- i = priv->stations[IWL_STA_ID].current_rate.s.rate;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- i = iwl3945_rate_index_from_plcp(i);
- if (i == -1)
- return sprintf(buf, "0\n");
-
- return sprintf(buf, "%d%s\n",
- (iwl3945_rates[i].ieee >> 1),
- (iwl3945_rates[i].ieee & 0x1) ? ".5" : "");
-}
-
-static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL);
-
static ssize_t store_retry_rate(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
static ssize_t show_channels(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct iwl3945_priv *priv = dev_get_drvdata(d);
- int len = 0, i;
- struct ieee80211_channel *channels = NULL;
- const struct ieee80211_hw_mode *hw_mode = NULL;
- int count = 0;
-
- if (!iwl3945_is_ready(priv))
- return -EAGAIN;
-
- hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211G);
- if (!hw_mode)
- hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211B);
- if (hw_mode) {
- channels = hw_mode->channels;
- count = hw_mode->num_channels;
- }
-
- len +=
- sprintf(&buf[len],
- "Displaying %d channels in 2.4GHz band "
- "(802.11bg):\n", count);
-
- for (i = 0; i < count; i++)
- len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
- channels[i].chan,
- channels[i].power_level,
- channels[i].
- flag & IEEE80211_CHAN_W_RADAR_DETECT ?
- " (IEEE 802.11h required)" : "",
- (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
- || (channels[i].
- flag &
- IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
- ", IBSS",
- channels[i].
- flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
- "active/passive" : "passive only");
-
- hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211A);
- if (hw_mode) {
- channels = hw_mode->channels;
- count = hw_mode->num_channels;
- } else {
- channels = NULL;
- count = 0;
- }
-
- len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
- "(802.11a):\n", count);
-
- for (i = 0; i < count; i++)
- len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
- channels[i].chan,
- channels[i].power_level,
- channels[i].
- flag & IEEE80211_CHAN_W_RADAR_DETECT ?
- " (IEEE 802.11h required)" : "",
- (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
- || (channels[i].
- flag &
- IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
- ", IBSS",
- channels[i].
- flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
- "active/passive" : "passive only");
-
- return len;
+ /* all this shit doesn't belong into sysfs anyway */
+ return 0;
}
static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
&dev_attr_measurement.attr,
#endif
&dev_attr_power_level.attr,
- &dev_attr_rate.attr,
&dev_attr_retry_rate.attr,
&dev_attr_rf_kill.attr,
&dev_attr_rs_window.attr,
&dev_attr_statistics.attr,
&dev_attr_status.attr,
&dev_attr_temperature.attr,
- &dev_attr_tune.attr,
&dev_attr_tx_power.attr,
NULL
static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int err = 0;
- u32 pci_id;
struct iwl3945_priv *priv;
struct ieee80211_hw *hw;
+ struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
int i;
DECLARE_MAC_BUF(mac);
priv->hw = hw;
priv->pci_dev = pdev;
+ priv->cfg = cfg;
/* Select antenna (may be helpful if only one antenna is connected) */
priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna;
priv->data_retry_limit = -1;
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
- priv->phymode = -1;
+ priv->band = IEEE80211_BAND_2GHZ;
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (!err)
priv->iw_mode = IEEE80211_IF_TYPE_STA;
- pci_id =
- (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device;
-
- switch (pci_id) {
- case 0x42221005: /* 0x4222 0x8086 0x1005 is BG SKU */
- case 0x42221034: /* 0x4222 0x8086 0x1034 is BG SKU */
- case 0x42271014: /* 0x4227 0x8086 0x1014 is BG SKU */
- case 0x42221044: /* 0x4222 0x8086 0x1044 is BG SKU */
- priv->is_abg = 0;
- break;
-
- /*
- * Rest are assumed ABG SKU -- if this is not the
- * case then the card will get the wrong 'Detected'
- * line in the kernel log however the code that
- * initializes the GEO table will detect no A-band
- * channels and remove the is_abg mask.
- */
- default:
- priv->is_abg = 1;
- break;
- }
-
printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n",
- priv->is_abg ? "A" : "");
+ ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
/* Device-specific setup */
if (iwl3945_hw_set_hw_setting(priv)) {
goto out_iounmap;
}
-#ifdef CONFIG_IWL3945_QOS
if (iwl3945_param_qos_enable)
priv->qos_data.qos_enable = 1;
priv->qos_data.qos_active = 0;
priv->qos_data.qos_cap.val = 0;
-#endif /* CONFIG_IWL3945_QOS */
- iwl3945_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+ iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
iwl3945_setup_deferred_work(priv);
iwl3945_setup_rx_handlers(priv);
IWL_ERROR("initializing geos failed: %d\n", err);
goto out_free_channel_map;
}
- iwl3945_reset_channel_flag(priv);
iwl3945_rate_control_register(priv->hw);
err = ieee80211_register_hw(priv->hw);
/******************************************************************************
*
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
#include <asm/div64.h>
+#include "iwl-eeprom.h"
+#include "iwl-core.h"
#include "iwl-4965.h"
#include "iwl-helpers.h"
-#ifdef CONFIG_IWL4965_DEBUG
-u32 iwl4965_debug_level;
-#endif
-
static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv,
struct iwl4965_tx_queue *txq);
#define VS
#endif
-#define IWLWIFI_VERSION "1.2.23k" VD VS
-#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation"
-#define DRV_VERSION IWLWIFI_VERSION
+#define DRV_VERSION IWLWIFI_VERSION VD VS
-/* Change firmware file name, using "-" and incrementing number,
- * *only* when uCode interface or architecture changes so that it
- * is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL4965_UCODE_API "-1"
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
return NULL;
}
-static const struct ieee80211_hw_mode *iwl4965_get_hw_mode(
- struct iwl4965_priv *priv, int mode)
+static const struct ieee80211_supported_band *iwl4965_get_hw_mode(
+ struct iwl4965_priv *priv, enum ieee80211_band band)
{
- int i;
-
- for (i = 0; i < 3; i++)
- if (priv->modes[i].mode == mode)
- return &priv->modes[i];
-
- return NULL;
+ return priv->hw->wiphy->bands[band];
}
static int iwl4965_is_empty_essid(const char *essid, int essid_len)
return escaped;
}
-static void iwl4965_print_hex_dump(int level, void *p, u32 len)
-{
-#ifdef CONFIG_IWL4965_DEBUG
- if (!(iwl4965_debug_level & level))
- return;
-
- print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
- p, len, 1);
-#endif
-}
-
/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
* DMA services
*
* See more detailed info in iwl-4965-hw.h.
***************************************************/
-static int iwl4965_queue_space(const struct iwl4965_queue *q)
+int iwl4965_queue_space(const struct iwl4965_queue *q)
{
int s = q->read_ptr - q->write_ptr;
return s;
}
-/**
- * iwl4965_queue_inc_wrap - increment queue index, wrap back to beginning
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl4965_queue_inc_wrap(int index, int n_bd)
-{
- return ++index & (n_bd - 1);
-}
-
-/**
- * iwl4965_queue_dec_wrap - decrement queue index, wrap back to end
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
-{
- return --index & (n_bd - 1);
-}
static inline int x2_queue_used(const struct iwl4965_queue *q, int i)
{
q->n_window = slots_num;
q->id = id;
- /* count must be power-of-two size, otherwise iwl4965_queue_inc_wrap
- * and iwl4965_queue_dec_wrap are broken. */
+ /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+ * and iwl_queue_dec_wrap are broken. */
BUG_ON(!is_power_of_2(count));
/* slots_num must be power-of-two size, otherwise
txq->need_update = 0;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
- * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */
+ * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
/* Initialize queue's high/low-water marks, and head/tail indexes */
/* first, empty all BD's */
for (; q->write_ptr != q->read_ptr;
- q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd))
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
iwl4965_hw_txq_free_tfd(priv, txq);
len = sizeof(struct iwl4965_cmd) * q->n_window;
ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
/* Increment and update queue's write index */
- q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
+ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
iwl4965_tx_queue_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
* in the staging RXON flag structure based on the phymode
*/
-static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode,
+static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv,
+ enum ieee80211_band band,
u16 channel)
{
- if (!iwl4965_get_channel_info(priv, phymode, channel)) {
+ if (!iwl4965_get_channel_info(priv, band, channel)) {
IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
- channel, phymode);
+ channel, band);
return -EINVAL;
}
if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
- (priv->phymode == phymode))
+ (priv->band == band))
return 0;
priv->staging_rxon.channel = cpu_to_le16(channel);
- if (phymode == MODE_IEEE80211A)
+ if (band == IEEE80211_BAND_5GHZ)
priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
else
priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
- priv->phymode = phymode;
+ priv->band = band;
- IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+ IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band);
return 0;
}
return priv->ibss_beacon->len;
}
-int iwl4965_rate_index_from_plcp(int plcp)
-{
- int i = 0;
-
- /* 4965 HT rate format */
- if (plcp & RATE_MCS_HT_MSK) {
- i = (plcp & 0xff);
-
- if (i >= IWL_RATE_MIMO_6M_PLCP)
- i = i - IWL_RATE_MIMO_6M_PLCP;
-
- i += IWL_FIRST_OFDM_RATE;
- /* skip 9M not supported in ht*/
- if (i >= IWL_RATE_9M_INDEX)
- i += 1;
- if ((i >= IWL_FIRST_OFDM_RATE) &&
- (i <= IWL_LAST_OFDM_RATE))
- return i;
-
- /* 4965 legacy rate format, search for match in table */
- } else {
- for (i = 0; i < ARRAY_SIZE(iwl4965_rates); i++)
- if (iwl4965_rates[i].plcp == (plcp &0xFF))
- return i;
- }
- return -1;
-}
-
static u8 iwl4965_rate_get_lowest_plcp(int rate_mask)
{
u8 i;
/******************************************************************************
*
- * EEPROM related functions
- *
- ******************************************************************************/
-
-static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac)
-{
- memcpy(mac, priv->eeprom.mac_address, 6);
-}
-
-static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
-{
- iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-}
-
-/**
- * iwl4965_eeprom_init - read EEPROM contents
- *
- * Load the EEPROM contents from adapter into priv->eeprom
- *
- * NOTE: This routine uses the non-debug IO access functions.
- */
-int iwl4965_eeprom_init(struct iwl4965_priv *priv)
-{
- u16 *e = (u16 *)&priv->eeprom;
- u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
- u32 r;
- int sz = sizeof(priv->eeprom);
- int rc;
- int i;
- u16 addr;
-
- /* The EEPROM structure has several padding buffers within it
- * and when adding new EEPROM maps is subject to programmer errors
- * which may be very difficult to identify without explicitly
- * checking the resulting size of the eeprom map. */
- BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
-
- if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
- IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
- return -ENOENT;
- }
-
- /* Make sure driver (instead of uCode) is allowed to read EEPROM */
- rc = iwl4965_eeprom_acquire_semaphore(priv);
- if (rc < 0) {
- IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
- return -ENOENT;
- }
-
- /* eeprom is an array of 16bit values */
- for (addr = 0; addr < sz; addr += sizeof(u16)) {
- _iwl4965_write32(priv, CSR_EEPROM_REG, addr << 1);
- _iwl4965_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
-
- for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
- i += IWL_EEPROM_ACCESS_DELAY) {
- r = _iwl4965_read_direct32(priv, CSR_EEPROM_REG);
- if (r & CSR_EEPROM_REG_READ_VALID_MSK)
- break;
- udelay(IWL_EEPROM_ACCESS_DELAY);
- }
-
- if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
- IWL_ERROR("Time out reading EEPROM[%d]", addr);
- rc = -ETIMEDOUT;
- goto done;
- }
- e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
- }
- rc = 0;
-
-done:
- iwl4965_eeprom_release_semaphore(priv);
- return rc;
-}
-
-/******************************************************************************
- *
* Misc. internal state and helper functions
*
******************************************************************************/
-#ifdef CONFIG_IWL4965_DEBUG
-
-/**
- * iwl4965_report_frame - dump frame to syslog during debug sessions
- *
- * You may hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good frames.
- *
- * TODO: This was originally written for 3945, need to audit for
- * proper operation with 4965.
- */
-void iwl4965_report_frame(struct iwl4965_priv *priv,
- struct iwl4965_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100)
-{
- u32 to_us;
- u32 print_summary = 0;
- u32 print_dump = 0; /* set to 1 to dump all frames' contents */
- u32 hundred = 0;
- u32 dataframe = 0;
- u16 fc;
- u16 seq_ctl;
- u16 channel;
- u16 phy_flags;
- int rate_sym;
- u16 length;
- u16 status;
- u16 bcn_tmr;
- u32 tsf_low;
- u64 tsf;
- u8 rssi;
- u8 agc;
- u16 sig_avg;
- u16 noise_diff;
- struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
- struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
- struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
- u8 *data = IWL_RX_DATA(pkt);
-
- /* MAC header */
- fc = le16_to_cpu(header->frame_control);
- seq_ctl = le16_to_cpu(header->seq_ctrl);
-
- /* metadata */
- channel = le16_to_cpu(rx_hdr->channel);
- phy_flags = le16_to_cpu(rx_hdr->phy_flags);
- rate_sym = rx_hdr->rate;
- length = le16_to_cpu(rx_hdr->len);
-
- /* end-of-frame status and timestamp */
- status = le32_to_cpu(rx_end->status);
- bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
- tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
- tsf = le64_to_cpu(rx_end->timestamp);
-
- /* signal statistics */
- rssi = rx_stats->rssi;
- agc = rx_stats->agc;
- sig_avg = le16_to_cpu(rx_stats->sig_avg);
- noise_diff = le16_to_cpu(rx_stats->noise_diff);
-
- to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
- /* if data frame is to us and all is good,
- * (optionally) print summary for only 1 out of every 100 */
- if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
- (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
- dataframe = 1;
- if (!group100)
- print_summary = 1; /* print each frame */
- else if (priv->framecnt_to_us < 100) {
- priv->framecnt_to_us++;
- print_summary = 0;
- } else {
- priv->framecnt_to_us = 0;
- print_summary = 1;
- hundred = 1;
- }
- } else {
- /* print summary for all other frames */
- print_summary = 1;
- }
-
- if (print_summary) {
- char *title;
- u32 rate;
-
- if (hundred)
- title = "100Frames";
- else if (fc & IEEE80211_FCTL_RETRY)
- title = "Retry";
- else if (ieee80211_is_assoc_response(fc))
- title = "AscRsp";
- else if (ieee80211_is_reassoc_response(fc))
- title = "RasRsp";
- else if (ieee80211_is_probe_response(fc)) {
- title = "PrbRsp";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_beacon(fc)) {
- title = "Beacon";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_atim(fc))
- title = "ATIM";
- else if (ieee80211_is_auth(fc))
- title = "Auth";
- else if (ieee80211_is_deauth(fc))
- title = "DeAuth";
- else if (ieee80211_is_disassoc(fc))
- title = "DisAssoc";
- else
- title = "Frame";
-
- rate = iwl4965_rate_index_from_plcp(rate_sym);
- if (rate == -1)
- rate = 0;
- else
- rate = iwl4965_rates[rate].ieee / 2;
-
- /* print frame summary.
- * MAC addresses show just the last byte (for brevity),
- * but you can hack it to show more, if you'd like to. */
- if (dataframe)
- IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
- "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
- title, fc, header->addr1[5],
- length, rssi, channel, rate);
- else {
- /* src/dst addresses assume managed mode */
- IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
- "src=0x%02x, rssi=%u, tim=%lu usec, "
- "phy=0x%02x, chnl=%d\n",
- title, fc, header->addr1[5],
- header->addr3[5], rssi,
- tsf_low - priv->scan_start_tsf,
- phy_flags, channel);
- }
- }
- if (print_dump)
- iwl4965_print_hex_dump(IWL_DL_RX, data, length);
-}
-#endif
static void iwl4965_unset_hw_setting(struct iwl4965_priv *priv)
{
return ret_rates;
}
-#ifdef CONFIG_IWL4965_HT
-void static iwl4965_set_ht_capab(struct ieee80211_hw *hw,
- struct ieee80211_ht_cap *ht_cap,
- u8 use_current_config);
-#endif
-
/**
* iwl4965_fill_probe_req - fill in all required fields and IE for probe request
*/
static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv,
- struct ieee80211_mgmt *frame,
- int left, int is_direct)
+ enum ieee80211_band band,
+ struct ieee80211_mgmt *frame,
+ int left, int is_direct)
{
int len = 0;
u8 *pos = NULL;
u16 active_rates, ret_rates, cck_rates, active_rate_basic;
#ifdef CONFIG_IWL4965_HT
- struct ieee80211_hw_mode *mode;
+ const struct ieee80211_supported_band *sband =
+ iwl4965_get_hw_mode(priv, band);
#endif /* CONFIG_IWL4965_HT */
/* Make sure there is enough space for the probe request,
len += 2 + *pos;
#ifdef CONFIG_IWL4965_HT
- mode = priv->hw->conf.mode;
- if (mode->ht_info.ht_supported) {
+ if (sband && sband->ht_info.ht_supported) {
+ struct ieee80211_ht_cap *ht_cap;
pos += (*pos) + 1;
*pos++ = WLAN_EID_HT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_ht_cap);
- iwl4965_set_ht_capab(priv->hw,
- (struct ieee80211_ht_cap *)pos, 0);
+ ht_cap = (struct ieee80211_ht_cap *)pos;
+ ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
+ memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
+ ht_cap->ampdu_params_info =(sband->ht_info.ampdu_factor &
+ IEEE80211_HT_CAP_AMPDU_FACTOR) |
+ ((sband->ht_info.ampdu_density << 2) &
+ IEEE80211_HT_CAP_AMPDU_DENSITY);
len += 2 + sizeof(struct ieee80211_ht_cap);
}
#endif /*CONFIG_IWL4965_HT */
/*
* QoS support
*/
-#ifdef CONFIG_IWL4965_QOS
static int iwl4965_send_qos_params_command(struct iwl4965_priv *priv,
struct iwl4965_qosparam_cmd *qos)
{
}
}
-#endif /* CONFIG_IWL4965_QOS */
/*
* Power management (not Tx power!) functions
*/
return 0;
}
-static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode)
+static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv,
+ enum ieee80211_band band)
{
- if (phymode == MODE_IEEE80211A) {
+ if (band == IEEE80211_BAND_5GHZ) {
priv->staging_rxon.flags &=
~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
| RXON_FLG_CCK_MSK);
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
#endif
- ch_info = iwl4965_get_channel_info(priv, priv->phymode,
+ ch_info = iwl4965_get_channel_info(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel));
if (!ch_info)
ch_info = &priv->channel_info[0];
priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
- if (is_channel_a_band(ch_info))
- priv->phymode = MODE_IEEE80211A;
- else
- priv->phymode = MODE_IEEE80211G;
+ priv->band = ch_info->band;
- iwl4965_set_flags_for_phymode(priv, priv->phymode);
+ iwl4965_set_flags_for_phymode(priv, priv->band);
priv->staging_rxon.ofdm_basic_rates =
(IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
const struct iwl4965_channel_info *ch_info;
ch_info = iwl4965_get_channel_info(priv,
- priv->phymode,
+ priv->band,
le16_to_cpu(priv->staging_rxon.channel));
if (!ch_info || !is_channel_ibss(ch_info)) {
goto drop_unlock;
}
- if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+ if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) {
IWL_ERROR("ERROR: No TX rate available.\n");
goto drop_unlock;
}
__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
seq_number += 0x10;
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
/* aggregation is on for this <sta,tid> */
- if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG)
+ if (ctl->flags & IEEE80211_TXCTL_AMPDU)
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
-#endif /* CONFIG_IWL4965_HT_AGG */
+ priv->stations[sta_id].tid[tid].tfds_in_queue++;
#endif /* CONFIG_IWL4965_HT */
}
out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys);
out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
-#ifdef CONFIG_IWL4965_HT_AGG
-#ifdef CONFIG_IWL4965_HT
- /* TODO: move this functionality to rate scaling */
- iwl4965_tl_get_stats(priv, hdr);
-#endif /* CONFIG_IWL4965_HT_AGG */
-#endif /*CONFIG_IWL4965_HT */
-
-
if (!ieee80211_get_morefrag(hdr)) {
txq->need_update = 1;
if (qc) {
iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
/* Tell device the write index *just past* this latest filled TFD */
- q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
+ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
rc = iwl4965_tx_queue_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
static void iwl4965_set_rate(struct iwl4965_priv *priv)
{
- const struct ieee80211_hw_mode *hw = NULL;
+ const struct ieee80211_supported_band *hw = NULL;
struct ieee80211_rate *rate;
int i;
- hw = iwl4965_get_hw_mode(priv, priv->phymode);
+ hw = iwl4965_get_hw_mode(priv, priv->band);
if (!hw) {
IWL_ERROR("Failed to set rate: unable to get hw mode\n");
return;
priv->active_rate = 0;
priv->active_rate_basic = 0;
- IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
- hw->mode == MODE_IEEE80211A ?
- 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
-
- for (i = 0; i < hw->num_rates; i++) {
- rate = &(hw->rates[i]);
- if ((rate->val < IWL_RATE_COUNT) &&
- (rate->flags & IEEE80211_RATE_SUPPORTED)) {
- IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
- rate->val, iwl4965_rates[rate->val].plcp,
- (rate->flags & IEEE80211_RATE_BASIC) ?
- "*" : "");
- priv->active_rate |= (1 << rate->val);
- if (rate->flags & IEEE80211_RATE_BASIC)
- priv->active_rate_basic |= (1 << rate->val);
- } else
- IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
- rate->val, iwl4965_rates[rate->val].plcp);
+ for (i = 0; i < hw->n_bitrates; i++) {
+ rate = &(hw->bitrates[i]);
+ if (rate->hw_value < IWL_RATE_COUNT)
+ priv->active_rate |= (1 << rate->hw_value);
}
IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
return 0;
}
- for (index = iwl4965_queue_inc_wrap(index, q->n_bd);
+ for (index = iwl_queue_inc_wrap(index, q->n_bd);
q->read_ptr != index;
- q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
if (txq_id != IWL_CMD_QUEUE_NUM) {
iwl4965_txstatus_to_ieee(priv,
&(txq->txb[txq->q.read_ptr]));
nfreed++;
}
- if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+/* if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) &&
(txq_id != IWL_CMD_QUEUE_NUM) &&
priv->mac80211_registered)
- ieee80211_wake_queue(priv->hw, txq_id);
+ ieee80211_wake_queue(priv->hw, txq_id); */
return nfreed;
*
******************************************************************************/
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv,
struct ieee80211_hdr *hdr)
*/
static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
struct iwl4965_ht_agg *agg,
- struct iwl4965_tx_resp *tx_resp,
+ struct iwl4965_tx_resp_agg *tx_resp,
u16 start_idx)
{
- u32 status;
- __le32 *frame_status = &tx_resp->status;
+ u16 status;
+ struct agg_tx_status *frame_status = &tx_resp->status;
struct ieee80211_tx_status *tx_status = NULL;
struct ieee80211_hdr *hdr = NULL;
int i, sh;
agg->frame_count = tx_resp->frame_count;
agg->start_idx = start_idx;
agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
- agg->bitmap0 = agg->bitmap1 = 0;
+ agg->bitmap = 0;
/* # frames attempted by Tx command */
if (agg->frame_count == 1) {
/* Only one frame was attempted; no block-ack will arrive */
- struct iwl4965_tx_queue *txq ;
- status = le32_to_cpu(frame_status[0]);
+ status = le16_to_cpu(frame_status[0].status);
+ seq = le16_to_cpu(frame_status[0].sequence);
+ idx = SEQ_TO_INDEX(seq);
+ txq_id = SEQ_TO_QUEUE(seq);
- txq_id = agg->txq_id;
- txq = &priv->txq[txq_id];
/* FIXME: code repetition */
- IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n",
- agg->frame_count, agg->start_idx);
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
+ agg->frame_count, agg->start_idx, idx);
- tx_status = &(priv->txq[txq_id].txb[txq->q.read_ptr].status);
+ tx_status = &(priv->txq[txq_id].txb[idx].status);
tx_status->retry_count = tx_resp->failure_frame;
tx_status->queue_number = status & 0xff;
- tx_status->queue_length = tx_resp->bt_kill_count;
- tx_status->queue_length |= tx_resp->failure_rts;
-
+ tx_status->queue_length = tx_resp->failure_rts;
+ tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU;
tx_status->flags = iwl4965_is_tx_success(status)?
IEEE80211_TX_STATUS_ACK : 0;
- tx_status->control.tx_rate =
- iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+ iwl4965_hwrate_to_tx_control(priv,
+ le32_to_cpu(tx_resp->rate_n_flags),
+ &tx_status->control);
/* FIXME: code repetition end */
IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
/* Construct bit-map of pending frames within Tx window */
for (i = 0; i < agg->frame_count; i++) {
u16 sc;
- status = le32_to_cpu(frame_status[i]);
- seq = status >> 16;
+ status = le16_to_cpu(frame_status[i].status);
+ seq = le16_to_cpu(frame_status[i].sequence);
idx = SEQ_TO_INDEX(seq);
txq_id = SEQ_TO_QUEUE(seq);
start, (u32)(bitmap & 0xFFFFFFFF));
}
- agg->bitmap0 = bitmap & 0xFFFFFFFF;
- agg->bitmap1 = bitmap >> 32;
+ agg->bitmap = bitmap;
agg->start_idx = start;
agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
- IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n",
+ IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
agg->frame_count, agg->start_idx,
- agg->bitmap0);
+ agg->bitmap);
if (bitmap)
agg->wait_for_ba = 1;
return 0;
}
#endif
-#endif
/**
* iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le32_to_cpu(tx_resp->status);
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
- int tid, sta_id;
-#endif
+ int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
+ struct ieee80211_hdr *hdr;
+ __le16 *qc;
#endif
if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
}
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
+ hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index);
+ qc = ieee80211_get_qos_ctrl(hdr);
+
+ if (qc)
+ tid = le16_to_cpu(*qc) & 0xf;
+
+ sta_id = iwl4965_get_ra_sta_id(priv, hdr);
+ if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
+ IWL_ERROR("Station not known\n");
+ return;
+ }
+
if (txq->sched_retry) {
const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
- struct ieee80211_hdr *hdr =
- iwl4965_tx_queue_get_hdr(priv, txq_id, index);
struct iwl4965_ht_agg *agg = NULL;
- __le16 *qc = ieee80211_get_qos_ctrl(hdr);
-
- if (qc == NULL) {
- IWL_ERROR("BUG_ON qc is null!!!!\n");
- return;
- }
- tid = le16_to_cpu(*qc) & 0xf;
-
- sta_id = iwl4965_get_ra_sta_id(priv, hdr);
- if (unlikely(sta_id == IWL_INVALID_STATION)) {
- IWL_ERROR("Station not known for\n");
+ if (!qc)
return;
- }
agg = &priv->stations[sta_id].tid[tid].agg;
- iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index);
+ iwl4965_tx_status_reply_tx(priv, agg,
+ (struct iwl4965_tx_resp_agg *)tx_resp, index);
if ((tx_resp->frame_count == 1) &&
!iwl4965_is_tx_success(status)) {
/* TODO: send BAR */
}
- if ((txq->q.read_ptr != (scd_ssn & 0xff))) {
- index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+ if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+ int freed;
+ index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
"%d index %d\n", scd_ssn , index);
- iwl4965_tx_queue_reclaim(priv, txq_id, index);
+ freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+
+ if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
+ txq_id >= 0 && priv->mac80211_registered &&
+ agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
+ ieee80211_wake_queue(priv->hw, txq_id);
+
+ iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
}
} else {
-#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
tx_status = &(txq->txb[txq->q.read_ptr].status);
tx_status->queue_number = status;
tx_status->queue_length = tx_resp->bt_kill_count;
tx_status->queue_length |= tx_resp->failure_rts;
-
tx_status->flags =
iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
-
- tx_status->control.tx_rate =
- iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+ iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
+ &tx_status->control);
IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
"retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status),
tx_resp->failure_frame);
IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
- if (index != -1)
- iwl4965_tx_queue_reclaim(priv, txq_id, index);
+ if (index != -1) {
+ int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
+#ifdef CONFIG_IWL4965_HT
+ if (tid != MAX_TID_COUNT)
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
+ (txq_id >= 0) &&
+ priv->mac80211_registered)
+ ieee80211_wake_queue(priv->hw, txq_id);
+ if (tid != MAX_TID_COUNT)
+ iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
+#endif
+ }
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
}
-#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
IWL_ERROR("Start IWL Error Log Dump:\n");
- IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
- priv->status, priv->config, count);
+ IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count);
}
desc = iwl4965_read_targ_mem(priv, base + 1 * sizeof(u32));
* atomic, make sure that inta covers all the interrupts that
* we've discovered, even if FH interrupt came in just after
* reading CSR_INT. */
- if (inta_fh & CSR_FH_INT_RX_MASK)
+ if (inta_fh & CSR49_FH_INT_RX_MASK)
inta |= CSR_INT_BIT_FH_RX;
- if (inta_fh & CSR_FH_INT_TX_MASK)
+ if (inta_fh & CSR49_FH_INT_TX_MASK)
inta |= CSR_INT_BIT_FH_TX;
/* Now service all interrupt bits discovered above. */
/* Queue restart only if RF_KILL switch was set to "kill"
* when we loaded driver, and is now set to "enable".
* After we're Alive, RF_KILL gets handled by
- * iwl_rx_card_state_notif() */
+ * iwl4965_rx_card_state_notif() */
if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
clear_bit(STATUS_RF_KILL_HW, &priv->status);
queue_work(priv->workqueue, &priv->restart);
* Based on band and channel number.
*/
const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965_priv *priv,
- int phymode, u16 channel)
+ enum ieee80211_band band, u16 channel)
{
int i;
- switch (phymode) {
- case MODE_IEEE80211A:
+ switch (band) {
+ case IEEE80211_BAND_5GHZ:
for (i = 14; i < priv->channel_count; i++) {
if (priv->channel_info[i].channel == channel)
return &priv->channel_info[i];
}
break;
-
- case MODE_IEEE80211B:
- case MODE_IEEE80211G:
+ case IEEE80211_BAND_2GHZ:
if (channel >= 1 && channel <= 14)
return &priv->channel_info[channel - 1];
break;
-
+ default:
+ BUG();
}
return NULL;
/* Loop through each band adding each of the channels */
for (ch = 0; ch < eeprom_ch_count; ch++) {
ch_info->channel = eeprom_ch_index[ch];
- ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
- MODE_IEEE80211A;
+ ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ;
/* permanently store EEPROM's channel regulatory flags
* and max power in channel info database. */
ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
ch_info->min_power = 0;
- IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+ IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x"
" %ddBm): Ad-Hoc %ssupported\n",
ch_info->channel,
is_channel_a_band(ch_info) ?
"5.2" : "2.4",
+ CHECK_AND_PRINT(VALID),
CHECK_AND_PRINT(IBSS),
CHECK_AND_PRINT(ACTIVE),
CHECK_AND_PRINT(RADAR),
/* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
for (band = 6; band <= 7; band++) {
- int phymode;
+ enum ieee80211_band ieeeband;
u8 fat_extension_chan;
iwl4965_init_band_reference(priv, band, &eeprom_ch_count,
&eeprom_ch_info, &eeprom_ch_index);
/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
- phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
+ ieeeband = (band == 6) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
/* Loop through each band adding each of the channels */
for (ch = 0; ch < eeprom_ch_count; ch++) {
fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
/* Set up driver's info for lower half */
- iwl4965_set_fat_chan_info(priv, phymode,
+ iwl4965_set_fat_chan_info(priv, ieeeband,
eeprom_ch_index[ch],
&(eeprom_ch_info[ch]),
fat_extension_chan);
/* Set up driver's info for upper half */
- iwl4965_set_fat_chan_info(priv, phymode,
+ iwl4965_set_fat_chan_info(priv, ieeeband,
(eeprom_ch_index[ch] + 4),
&(eeprom_ch_info[ch]),
HT_IE_EXT_CHANNEL_BELOW);
#define IWL_PASSIVE_DWELL_BASE (100)
#define IWL_CHANNEL_TUNE_TIME 5
-static inline u16 iwl4965_get_active_dwell_time(struct iwl4965_priv *priv, int phymode)
+static inline u16 iwl4965_get_active_dwell_time(struct iwl4965_priv *priv,
+ enum ieee80211_band band)
{
- if (phymode == MODE_IEEE80211A)
+ if (band == IEEE80211_BAND_5GHZ)
return IWL_ACTIVE_DWELL_TIME_52;
else
return IWL_ACTIVE_DWELL_TIME_24;
}
-static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, int phymode)
+static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv,
+ enum ieee80211_band band)
{
- u16 active = iwl4965_get_active_dwell_time(priv, phymode);
- u16 passive = (phymode != MODE_IEEE80211A) ?
+ u16 active = iwl4965_get_active_dwell_time(priv, band);
+ u16 passive = (band != IEEE80211_BAND_5GHZ) ?
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
return passive;
}
-static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode,
+static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv,
+ enum ieee80211_band band,
u8 is_active, u8 direct_mask,
struct iwl4965_scan_channel *scan_ch)
{
const struct ieee80211_channel *channels = NULL;
- const struct ieee80211_hw_mode *hw_mode;
+ const struct ieee80211_supported_band *sband;
const struct iwl4965_channel_info *ch_info;
u16 passive_dwell = 0;
u16 active_dwell = 0;
int added, i;
- hw_mode = iwl4965_get_hw_mode(priv, phymode);
- if (!hw_mode)
+ sband = iwl4965_get_hw_mode(priv, band);
+ if (!sband)
return 0;
- channels = hw_mode->channels;
+ channels = sband->channels;
- active_dwell = iwl4965_get_active_dwell_time(priv, phymode);
- passive_dwell = iwl4965_get_passive_dwell_time(priv, phymode);
+ active_dwell = iwl4965_get_active_dwell_time(priv, band);
+ passive_dwell = iwl4965_get_passive_dwell_time(priv, band);
- for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
- if (channels[i].chan ==
+ for (i = 0, added = 0; i < sband->n_channels; i++) {
+ if (ieee80211_frequency_to_channel(channels[i].center_freq) ==
le16_to_cpu(priv->active_rxon.channel)) {
if (iwl4965_is_associated(priv)) {
IWL_DEBUG_SCAN
} else if (priv->only_active_channel)
continue;
- scan_ch->channel = channels[i].chan;
+ scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq);
- ch_info = iwl4965_get_channel_info(priv, phymode,
+ ch_info = iwl4965_get_channel_info(priv, band,
scan_ch->channel);
if (!is_channel_valid(ch_info)) {
IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
}
if (!is_active || is_channel_passive(ch_info) ||
- !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+ (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
scan_ch->type = 0; /* passive */
else
scan_ch->type = 1; /* active */
/* scan_pwr_info->tpc.dsp_atten; */
/*scan_pwr_info->tpc.tx_gain; */
- if (phymode == MODE_IEEE80211A)
+ if (band == IEEE80211_BAND_5GHZ)
scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
else {
scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
return added;
}
-static void iwl4965_reset_channel_flag(struct iwl4965_priv *priv)
-{
- int i, j;
- for (i = 0; i < 3; i++) {
- struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
- for (j = 0; j < hw_mode->num_channels; j++)
- hw_mode->channels[j].flag = hw_mode->channels[j].val;
- }
-}
-
static void iwl4965_init_hw_rates(struct iwl4965_priv *priv,
struct ieee80211_rate *rates)
{
int i;
for (i = 0; i < IWL_RATE_COUNT; i++) {
- rates[i].rate = iwl4965_rates[i].ieee * 5;
- rates[i].val = i; /* Rate scaling will work on indexes */
- rates[i].val2 = i;
- rates[i].flags = IEEE80211_RATE_SUPPORTED;
- /* Only OFDM have the bits-per-symbol set */
- if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
- rates[i].flags |= IEEE80211_RATE_OFDM;
- else {
+ rates[i].bitrate = iwl4965_rates[i].ieee * 5;
+ rates[i].hw_value = i; /* Rate scaling will work on indexes */
+ rates[i].hw_value_short = i;
+ rates[i].flags = 0;
+ if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
/*
- * If CCK 1M then set rate flag to CCK else CCK_2
- * which is CCK | PREAMBLE2
+ * If CCK != 1M then set short preamble rate flag.
*/
- rates[i].flags |= (iwl4965_rates[i].plcp == 10) ?
- IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+ rates[i].flags |=
+ (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ?
+ 0 : IEEE80211_RATE_SHORT_PREAMBLE;
}
-
- /* Set up which ones are basic rates... */
- if (IWL_BASIC_RATES_MASK & (1 << i))
- rates[i].flags |= IEEE80211_RATE_BASIC;
}
}
static int iwl4965_init_geos(struct iwl4965_priv *priv)
{
struct iwl4965_channel_info *ch;
- struct ieee80211_hw_mode *modes;
+ struct ieee80211_supported_band *sband;
struct ieee80211_channel *channels;
struct ieee80211_channel *geo_ch;
struct ieee80211_rate *rates;
int i = 0;
- enum {
- A = 0,
- B = 1,
- G = 2,
- };
- int mode_count = 3;
- if (priv->modes) {
+ if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
+ priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
IWL_DEBUG_INFO("Geography modes already initialized.\n");
set_bit(STATUS_GEO_CONFIGURED, &priv->status);
return 0;
}
- modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
- GFP_KERNEL);
- if (!modes)
- return -ENOMEM;
-
channels = kzalloc(sizeof(struct ieee80211_channel) *
priv->channel_count, GFP_KERNEL);
- if (!channels) {
- kfree(modes);
+ if (!channels)
return -ENOMEM;
- }
- rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+ rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
GFP_KERNEL);
if (!rates) {
- kfree(modes);
kfree(channels);
return -ENOMEM;
}
- /* 0 = 802.11a
- * 1 = 802.11b
- * 2 = 802.11g
- */
-
/* 5.2GHz channels start after the 2.4GHz channels */
- modes[A].mode = MODE_IEEE80211A;
- modes[A].channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)];
- modes[A].rates = rates;
- modes[A].num_rates = 8; /* just OFDM */
- modes[A].rates = &rates[4];
- modes[A].num_channels = 0;
-#ifdef CONFIG_IWL4965_HT
- iwl4965_init_ht_hw_capab(&modes[A].ht_info, MODE_IEEE80211A);
-#endif
+ sband = &priv->bands[IEEE80211_BAND_5GHZ];
+ sband->channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)];
+ /* just OFDM */
+ sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
+ sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
- modes[B].mode = MODE_IEEE80211B;
- modes[B].channels = channels;
- modes[B].rates = rates;
- modes[B].num_rates = 4; /* just CCK */
- modes[B].num_channels = 0;
-
- modes[G].mode = MODE_IEEE80211G;
- modes[G].channels = channels;
- modes[G].rates = rates;
- modes[G].num_rates = 12; /* OFDM & CCK */
- modes[G].num_channels = 0;
-#ifdef CONFIG_IWL4965_HT
- iwl4965_init_ht_hw_capab(&modes[G].ht_info, MODE_IEEE80211G);
-#endif
+ iwl4965_init_ht_hw_capab(&sband->ht_info, IEEE80211_BAND_5GHZ);
+
+ sband = &priv->bands[IEEE80211_BAND_2GHZ];
+ sband->channels = channels;
+ /* OFDM & CCK */
+ sband->bitrates = rates;
+ sband->n_bitrates = IWL_RATE_COUNT;
+
+ iwl4965_init_ht_hw_capab(&sband->ht_info, IEEE80211_BAND_2GHZ);
priv->ieee_channels = channels;
priv->ieee_rates = rates;
iwl4965_init_hw_rates(priv, rates);
- for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+ for (i = 0; i < priv->channel_count; i++) {
ch = &priv->channel_info[i];
- if (!is_channel_valid(ch)) {
- IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
- "skipping.\n",
- ch->channel, is_channel_a_band(ch) ?
- "5.2" : "2.4");
+ /* FIXME: might be removed if scan is OK */
+ if (!is_channel_valid(ch))
continue;
- }
- if (is_channel_a_band(ch)) {
- geo_ch = &modes[A].channels[modes[A].num_channels++];
- } else {
- geo_ch = &modes[B].channels[modes[B].num_channels++];
- modes[G].num_channels++;
- }
+ if (is_channel_a_band(ch))
+ sband = &priv->bands[IEEE80211_BAND_5GHZ];
+ else
+ sband = &priv->bands[IEEE80211_BAND_2GHZ];
- geo_ch->freq = ieee80211chan2mhz(ch->channel);
- geo_ch->chan = ch->channel;
- geo_ch->power_level = ch->max_power_avg;
- geo_ch->antenna_max = 0xff;
+ geo_ch = &sband->channels[sband->n_channels++];
+
+ geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel);
+ geo_ch->max_power = ch->max_power_avg;
+ geo_ch->max_antenna_gain = 0xff;
+ geo_ch->hw_value = ch->channel;
if (is_channel_valid(ch)) {
- geo_ch->flag = IEEE80211_CHAN_W_SCAN;
- if (ch->flags & EEPROM_CHANNEL_IBSS)
- geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+ if (!(ch->flags & EEPROM_CHANNEL_IBSS))
+ geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
- if (ch->flags & EEPROM_CHANNEL_ACTIVE)
- geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+ if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
+ geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
if (ch->flags & EEPROM_CHANNEL_RADAR)
- geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+ geo_ch->flags |= IEEE80211_CHAN_RADAR;
if (ch->max_power_avg > priv->max_channel_txpower_limit)
priv->max_channel_txpower_limit =
ch->max_power_avg;
+ } else {
+ geo_ch->flags |= IEEE80211_CHAN_DISABLED;
}
- geo_ch->val = geo_ch->flag;
+ /* Save flags for reg domain usage */
+ geo_ch->orig_flags = geo_ch->flags;
+
+ IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n",
+ ch->channel, geo_ch->center_freq,
+ is_channel_a_band(ch) ? "5.2" : "2.4",
+ geo_ch->flags & IEEE80211_CHAN_DISABLED ?
+ "restricted" : "valid",
+ geo_ch->flags);
}
- if ((modes[A].num_channels == 0) && priv->is_abg) {
+ if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
+ priv->cfg->sku & IWL_SKU_A) {
printk(KERN_INFO DRV_NAME
": Incorrectly detected BG card as ABG. Please send "
"your PCI ID 0x%04X:0x%04X to maintainer.\n",
priv->pci_dev->device, priv->pci_dev->subsystem_device);
- priv->is_abg = 0;
+ priv->cfg->sku &= ~IWL_SKU_A;
}
printk(KERN_INFO DRV_NAME
": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
- modes[G].num_channels, modes[A].num_channels);
+ priv->bands[IEEE80211_BAND_2GHZ].n_channels,
+ priv->bands[IEEE80211_BAND_5GHZ].n_channels);
- /*
- * NOTE: We register these in preference of order -- the
- * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
- * a phymode based on rates or AP capabilities but seems to
- * configure it purely on if the channel being configured
- * is supported by a mode -- and the first match is taken
- */
+ priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->bands[IEEE80211_BAND_2GHZ];
+ priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ];
- if (modes[G].num_channels)
- ieee80211_register_hwmode(priv->hw, &modes[G]);
- if (modes[B].num_channels)
- ieee80211_register_hwmode(priv->hw, &modes[B]);
- if (modes[A].num_channels)
- ieee80211_register_hwmode(priv->hw, &modes[A]);
-
- priv->modes = modes;
set_bit(STATUS_GEO_CONFIGURED, &priv->status);
return 0;
*/
static void iwl4965_free_geos(struct iwl4965_priv *priv)
{
- kfree(priv->modes);
kfree(priv->ieee_channels);
kfree(priv->ieee_rates);
clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
struct iwl4965_ucode *ucode;
int ret;
const struct firmware *ucode_raw;
- const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
+ const char *name = priv->cfg->fw_name;
u8 *src;
size_t len;
u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
int rc = 0;
struct iwl4965_scan_cmd *scan;
struct ieee80211_conf *conf = NULL;
+ u16 cmd_len;
+ enum ieee80211_band band;
u8 direct_mask;
- int phymode;
conf = ieee80211_get_hw_conf(priv->hw);
} else
direct_mask = 0;
- /* We don't build a direct scan probe request; the uCode will do
- * that based on the direct_mask added to each channel entry */
- scan->tx_cmd.len = cpu_to_le16(
- iwl4965_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
- IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
- /* flags + rate selection */
-
- scan->tx_cmd.tx_flags |= cpu_to_le32(0x200);
switch (priv->scan_bands) {
case 2:
RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
scan->good_CRC_th = 0;
- phymode = MODE_IEEE80211G;
+ band = IEEE80211_BAND_2GHZ;
break;
case 1:
iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
RATE_MCS_ANT_B_MSK);
scan->good_CRC_th = IWL_GOOD_CRC_TH;
- phymode = MODE_IEEE80211A;
+ band = IEEE80211_BAND_5GHZ;
break;
default:
goto done;
}
+ /* We don't build a direct scan probe request; the uCode will do
+ * that based on the direct_mask added to each channel entry */
+ cmd_len = iwl4965_fill_probe_req(priv, band,
+ (struct ieee80211_mgmt *)scan->data,
+ IWL_MAX_SCAN_SIZE - sizeof(*scan), 0);
+
+ scan->tx_cmd.len = cpu_to_le16(cmd_len);
/* select Rx chains */
/* Force use of chains B and C (0x6) for scan Rx.
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
- if (direct_mask)
+ if (direct_mask) {
IWL_DEBUG_SCAN
("Initiating direct scan for %s.\n",
iwl4965_escape_essid(priv->essid, priv->essid_len));
- else
+ scan->channel_count =
+ iwl4965_get_channels_for_scan(
+ priv, band, 1, /* active */
+ direct_mask,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+ } else {
IWL_DEBUG_SCAN("Initiating indirect scan.\n");
-
- scan->channel_count =
- iwl4965_get_channels_for_scan(
- priv, phymode, 1, /* active */
- direct_mask,
- (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+ scan->channel_count =
+ iwl4965_get_channels_for_scan(
+ priv, band, 0, /* passive */
+ direct_mask,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+ }
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
scan->channel_count * sizeof(struct iwl4965_scan_channel);
if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
priv->assoc_station_added = 1;
-#ifdef CONFIG_IWL4965_QOS
iwl4965_activate_qos(priv, 0);
-#endif /* CONFIG_IWL4965_QOS */
+
/* we have just associated, don't start scan too early */
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
mutex_unlock(&priv->mutex);
}
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
- ctl->tx_rate);
+ ctl->tx_rate->bitrate);
if (iwl4965_tx_skb(priv, skb, ctl))
dev_kfree_skb_any(skb);
int ret = 0;
mutex_lock(&priv->mutex);
- IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+ IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
spin_lock_irqsave(&priv->lock, flags);
- ch_info = iwl4965_get_channel_info(priv, conf->phymode, conf->channel);
+ ch_info = iwl4965_get_channel_info(priv, conf->channel->band,
+ ieee80211_frequency_to_channel(conf->channel->center_freq));
if (!is_channel_valid(ch_info)) {
- IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
- conf->channel, conf->phymode);
IWL_DEBUG_MAC80211("leave - invalid channel\n");
spin_unlock_irqrestore(&priv->lock, flags);
ret = -EINVAL;
}
#ifdef CONFIG_IWL4965_HT
- /* if we are switching fron ht to 2.4 clear flags
+ /* if we are switching from ht to 2.4 clear flags
* from any ht related info since 2.4 does not
* support ht */
- if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel)
+ if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel->hw_value)
#ifdef IEEE80211_CONF_CHANNEL_SWITCH
&& !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH)
#endif
priv->staging_rxon.flags = 0;
#endif /* CONFIG_IWL4965_HT */
- iwl4965_set_rxon_channel(priv, conf->phymode, conf->channel);
+ iwl4965_set_rxon_channel(priv, conf->channel->band,
+ ieee80211_frequency_to_channel(conf->channel->center_freq));
- iwl4965_set_flags_for_phymode(priv, conf->phymode);
+ iwl4965_set_flags_for_phymode(priv, conf->channel->band);
/* The list of supported rates and rate mask can be different
- * for each phymode; since the phymode may have changed, reset
+ * for each band; since the band may have changed, reset
* the rate mask to what mac80211 lists */
iwl4965_set_rate(priv);
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
iwl4965_commit_rxon(priv);
-#ifdef CONFIG_IWL4965_QOS
iwl4965_activate_qos(priv, 1);
-#endif
iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
}
iwl4965_send_beacon_cmd(priv);
if (conf == NULL)
return -EIO;
+ if (priv->vif != vif) {
+ IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
(!conf->beacon || !conf->ssid_len)) {
IWL_DEBUG_MAC80211
if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
!(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
*/
- if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
- IWL_DEBUG_MAC80211("leave - scanning\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- if (priv->vif != vif) {
- IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
if (!conf->bssid) {
}
if (changes & BSS_CHANGED_ERP_CTS_PROT) {
- if (bss_conf->use_cts_prot && (priv->phymode != MODE_IEEE80211A))
+ if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
const struct ieee80211_tx_queue_params *params)
{
struct iwl4965_priv *priv = hw->priv;
-#ifdef CONFIG_IWL4965_QOS
unsigned long flags;
int q;
-#endif /* CONFIG_IWL4965_QOS */
IWL_DEBUG_MAC80211("enter\n");
return 0;
}
-#ifdef CONFIG_IWL4965_QOS
if (!priv->qos_data.qos_enable) {
priv->qos_data.qos_active = 0;
IWL_DEBUG_MAC80211("leave - qos not enabled\n");
priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
priv->qos_data.def_qos_parm.ac[q].edca_txop =
- cpu_to_le16((params->burst_time * 100));
+ cpu_to_le16((params->txop * 32));
priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
priv->qos_data.qos_active = 1;
mutex_unlock(&priv->mutex);
-#endif /*CONFIG_IWL4965_QOS */
-
IWL_DEBUG_MAC80211("leave\n");
return 0;
}
spin_lock_irqsave(&priv->lock, flags);
memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
spin_unlock_irqrestore(&priv->lock, flags);
-#ifdef CONFIG_IWL4965_HT_AGG
-/* if (priv->lq_mngr.agg_ctrl.granted_ba)
- iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/
-
- memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl4965_agg_control));
- priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10;
- priv->lq_mngr.agg_ctrl.ba_timeout = 5000;
- priv->lq_mngr.agg_ctrl.auto_agg = 1;
-
- if (priv->lq_mngr.agg_ctrl.auto_agg)
- priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED;
-#endif /*CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
-#ifdef CONFIG_IWL4965_QOS
iwl4965_reset_qos(priv);
-#endif
cancel_delayed_work(&priv->post_associate);
IWL_DEBUG_MAC80211("leave\n");
spin_unlock_irqrestore(&priv->lock, flags);
-#ifdef CONFIG_IWL4965_QOS
iwl4965_reset_qos(priv);
-#endif
queue_work(priv->workqueue, &priv->post_associate.work);
iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
iwl_conf->max_amsdu_size =
!!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+
iwl_conf->supported_chan_width =
!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
+ iwl_conf->extension_chan_offset =
+ ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+ /* If no above or below channel supplied disable FAT channel */
+ if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE &&
+ iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW)
+ iwl_conf->supported_chan_width = 0;
+
iwl_conf->tx_mimo_ps_mode =
(u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
iwl_conf->control_channel = ht_bss_conf->primary_channel;
- iwl_conf->extension_chan_offset =
- ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
iwl_conf->tx_chan_width =
!!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
iwl_conf->ht_protection =
return 0;
}
-static void iwl4965_set_ht_capab(struct ieee80211_hw *hw,
- struct ieee80211_ht_cap *ht_cap,
- u8 use_current_config)
-{
- struct ieee80211_conf *conf = &hw->conf;
- struct ieee80211_hw_mode *mode = conf->mode;
-
- if (use_current_config) {
- ht_cap->cap_info = cpu_to_le16(conf->ht_conf.cap);
- memcpy(ht_cap->supp_mcs_set,
- conf->ht_conf.supp_mcs_set, 16);
- } else {
- ht_cap->cap_info = cpu_to_le16(mode->ht_info.cap);
- memcpy(ht_cap->supp_mcs_set,
- mode->ht_info.supp_mcs_set, 16);
- }
- ht_cap->ampdu_params_info =
- (mode->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
- ((mode->ht_info.ampdu_density << 2) &
- IEEE80211_HT_CAP_AMPDU_DENSITY);
-}
-
#endif /*CONFIG_IWL4965_HT*/
/*****************************************************************************
static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
store_filter_flags);
-static ssize_t show_tune(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
-
- return sprintf(buf, "0x%04X\n",
- (priv->phymode << 8) |
- le16_to_cpu(priv->active_rxon.channel));
-}
-
-static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode);
-
-static ssize_t store_tune(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
- char *p = (char *)buf;
- u16 tune = simple_strtoul(p, &p, 0);
- u8 phymode = (tune >> 8) & 0xff;
- u16 channel = tune & 0xff;
-
- IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
-
- mutex_lock(&priv->mutex);
- if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
- (priv->phymode != phymode)) {
- const struct iwl4965_channel_info *ch_info;
-
- ch_info = iwl4965_get_channel_info(priv, phymode, channel);
- if (!ch_info) {
- IWL_WARNING("Requested invalid phymode/channel "
- "combination: %d %d\n", phymode, channel);
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- /* Cancel any currently running scans... */
- if (iwl4965_scan_cancel_timeout(priv, 100))
- IWL_WARNING("Could not cancel scan.\n");
- else {
- IWL_DEBUG_INFO("Committing phymode and "
- "rxon.channel = %d %d\n",
- phymode, channel);
-
- iwl4965_set_rxon_channel(priv, phymode, channel);
- iwl4965_set_flags_for_phymode(priv, phymode);
-
- iwl4965_set_rate(priv);
- iwl4965_commit_rxon(priv);
- }
- }
- mutex_unlock(&priv->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
-
#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
static ssize_t show_measurement(struct device *d,
static ssize_t show_channels(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct iwl4965_priv *priv = dev_get_drvdata(d);
- int len = 0, i;
- struct ieee80211_channel *channels = NULL;
- const struct ieee80211_hw_mode *hw_mode = NULL;
- int count = 0;
-
- if (!iwl4965_is_ready(priv))
- return -EAGAIN;
-
- hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211G);
- if (!hw_mode)
- hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211B);
- if (hw_mode) {
- channels = hw_mode->channels;
- count = hw_mode->num_channels;
- }
-
- len +=
- sprintf(&buf[len],
- "Displaying %d channels in 2.4GHz band "
- "(802.11bg):\n", count);
-
- for (i = 0; i < count; i++)
- len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
- channels[i].chan,
- channels[i].power_level,
- channels[i].
- flag & IEEE80211_CHAN_W_RADAR_DETECT ?
- " (IEEE 802.11h required)" : "",
- (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
- || (channels[i].
- flag &
- IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
- ", IBSS",
- channels[i].
- flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
- "active/passive" : "passive only");
-
- hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211A);
- if (hw_mode) {
- channels = hw_mode->channels;
- count = hw_mode->num_channels;
- } else {
- channels = NULL;
- count = 0;
- }
-
- len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
- "(802.11a):\n", count);
-
- for (i = 0; i < count; i++)
- len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
- channels[i].chan,
- channels[i].power_level,
- channels[i].
- flag & IEEE80211_CHAN_W_RADAR_DETECT ?
- " (IEEE 802.11h required)" : "",
- (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
- || (channels[i].
- flag &
- IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
- ", IBSS",
- channels[i].
- flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
- "active/passive" : "passive only");
-
- return len;
+ /* all this shit doesn't belong into sysfs anyway */
+ return 0;
}
static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
&dev_attr_statistics.attr,
&dev_attr_status.attr,
&dev_attr_temperature.attr,
- &dev_attr_tune.attr,
&dev_attr_tx_power.attr,
NULL
#ifdef CONFIG_IWL4965_HT
.conf_ht = iwl4965_mac_conf_ht,
.ampdu_action = iwl4965_mac_ampdu_action,
-#ifdef CONFIG_IWL4965_HT_AGG
- .ht_tx_agg_start = iwl4965_mac_ht_tx_agg_start,
- .ht_tx_agg_stop = iwl4965_mac_ht_tx_agg_stop,
-#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
.hw_scan = iwl4965_mac_hw_scan
};
int err = 0;
struct iwl4965_priv *priv;
struct ieee80211_hw *hw;
+ struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
int i;
DECLARE_MAC_BUF(mac);
IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
priv = hw->priv;
priv->hw = hw;
+ priv->cfg = cfg;
priv->pci_dev = pdev;
priv->antenna = (enum iwl4965_antenna)iwl4965_param_antenna;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
#ifdef CONFIG_IWL4965_HT
-#ifdef CONFIG_IWL4965_HT_AGG
/* Enhanced value; more queues, to support 11n aggregation */
hw->queues = 16;
-#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
spin_lock_init(&priv->lock);
priv->data_retry_limit = -1;
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
- priv->phymode = -1;
+ priv->band = IEEE80211_BAND_2GHZ;
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (!err)
/* Choose which receivers/antennas to use */
iwl4965_set_rxon_chain(priv);
+
printk(KERN_INFO DRV_NAME
- ": Detected Intel Wireless WiFi Link 4965AGN\n");
+ ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
/* Device-specific setup */
if (iwl4965_hw_set_hw_setting(priv)) {
goto out_iounmap;
}
-#ifdef CONFIG_IWL4965_QOS
if (iwl4965_param_qos_enable)
priv->qos_data.qos_enable = 1;
priv->qos_data.qos_active = 0;
priv->qos_data.qos_cap.val = 0;
-#endif /* CONFIG_IWL4965_QOS */
- iwl4965_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+ iwl4965_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
iwl4965_setup_deferred_work(priv);
iwl4965_setup_rx_handlers(priv);
goto out_remove_sysfs;
}
/* Read the EEPROM */
- err = iwl4965_eeprom_init(priv);
+ err = iwl_eeprom_init(priv);
if (err) {
IWL_ERROR("Unable to init EEPROM\n");
goto out_remove_sysfs;
}
/* MAC Address location in EEPROM same for 3945/4965 */
- get_eeprom_mac(priv, priv->mac_addr);
+ iwl_eeprom_get_mac(priv, priv->mac_addr);
IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
IWL_ERROR("initializing geos failed: %d\n", err);
goto out_free_channel_map;
}
- iwl4965_reset_channel_flag(priv);
iwl4965_rate_control_register(priv->hw);
err = ieee80211_register_hw(priv->hw);
escape_essid(assoc_req->ssid, assoc_req->ssid_len));
if (assoc_req->mode == IW_MODE_INFRA) {
lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
- assoc_req->ssid_len, 0);
+ assoc_req->ssid_len);
bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
* scan data will cause us to join a non-existant adhoc network
*/
lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
- assoc_req->ssid_len, 1);
+ assoc_req->ssid_len);
/* Search for the requested SSID in the scan table */
bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
return ret;
}
-void lbs_sync_channel(struct work_struct *work)
-{
- struct lbs_private *priv = container_of(work, struct lbs_private,
- sync_channel);
-
- lbs_deb_enter(LBS_DEB_ASSOC);
- if (lbs_update_channel(priv))
- lbs_pr_info("Channel synchronization failed.");
- lbs_deb_leave(LBS_DEB_ASSOC);
-}
-
static int assoc_helper_channel(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
- ret = lbs_prepare_and_send_command(priv,
- CMD_802_11_KEY_MATERIAL,
- CMD_ACT_SET,
- CMD_OPTION_WAITFORRSP,
- 0, assoc_req);
+ ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
assoc_req->flags = flags;
}
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
- ret = lbs_prepare_and_send_command(priv,
- CMD_802_11_KEY_MATERIAL,
- CMD_ACT_SET,
- CMD_OPTION_WAITFORRSP,
- 0, assoc_req);
+ ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
assoc_req->flags = flags;
}
{
int ret = 0;
- lbs_deb_enter(LBS_DEB_ASSOC);
-
if (priv->connect_status != LBS_CONNECTED)
return 0;
+ lbs_deb_enter(LBS_DEB_ASSOC);
if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
lbs_deb_assoc("Deauthenticating due to new SSID\n");
ret = 1;
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return 0;
+ return ret;
}
}
if (success) {
- lbs_deb_assoc("ASSOC: associated to '%s', %s\n",
- escape_essid(priv->curbssparams.ssid,
- priv->curbssparams.ssid_len),
+ lbs_deb_assoc("associated to %s\n",
print_mac(mac, priv->curbssparams.bssid));
lbs_prepare_and_send_command(priv,
CMD_802_11_RSSI,
void lbs_association_worker(struct work_struct *work);
struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
-void lbs_sync_channel(struct work_struct *work);
#endif /* _LBS_ASSOC_H */
return ret;
}
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
- struct enc_key * pkey)
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
+ struct enc_key *key)
{
lbs_deb_enter(LBS_DEB_CMD);
- if (pkey->flags & KEY_INFO_WPA_ENABLED) {
- pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
- }
- if (pkey->flags & KEY_INFO_WPA_UNICAST) {
- pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
- }
- if (pkey->flags & KEY_INFO_WPA_MCAST) {
- pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
- }
+ if (key->flags & KEY_INFO_WPA_ENABLED)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
+ if (key->flags & KEY_INFO_WPA_UNICAST)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+ if (key->flags & KEY_INFO_WPA_MCAST)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+
+ keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ keyparam->keytypeid = cpu_to_le16(key->type);
+ keyparam->keylen = cpu_to_le16(key->len);
+ memcpy(keyparam->key, key->key, key->len);
- pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
- pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
- pkeyparamset->keylen = cpu_to_le16(pkey->len);
- memcpy(pkeyparamset->key, pkey->key, pkey->len);
- pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
- + sizeof(pkeyparamset->keyinfo)
- + sizeof(pkeyparamset->keylen)
- + sizeof(pkeyparamset->key));
+ /* Length field doesn't include the {type,length} header */
+ keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
lbs_deb_leave(LBS_DEB_CMD);
}
-static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action,
- u32 cmd_oid, void *pdata_buf)
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc)
{
- struct cmd_ds_802_11_key_material *pkeymaterial =
- &cmd->params.keymaterial;
- struct assoc_request * assoc_req = pdata_buf;
+ struct cmd_ds_802_11_key_material cmd;
int ret = 0;
int index = 0;
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
- pkeymaterial->action = cpu_to_le16(cmd_action);
+ cmd.action = cpu_to_le16(cmd_action);
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
if (cmd_action == CMD_ACT_GET) {
- cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
- ret = 0;
- goto done;
- }
+ cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
+ } else {
+ memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
- memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
+ if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
+ set_one_wpa_key(&cmd.keyParamSet[index],
+ &assoc->wpa_unicast_key);
+ index++;
+ }
- if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
- set_one_wpa_key(&pkeymaterial->keyParamSet[index],
- &assoc_req->wpa_unicast_key);
- index++;
- }
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
+ set_one_wpa_key(&cmd.keyParamSet[index],
+ &assoc->wpa_mcast_key);
+ index++;
+ }
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
- set_one_wpa_key(&pkeymaterial->keyParamSet[index],
- &assoc_req->wpa_mcast_key);
- index++;
+ /* The common header and as many keys as we included */
+ cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
+ keyParamSet[index]));
}
+ ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+ /* Copy the returned key to driver private data */
+ if (!ret && cmd_action == CMD_ACT_GET) {
+ void *buf_ptr = cmd.keyParamSet;
+ void *resp_end = &(&cmd)[1];
+
+ while (buf_ptr < resp_end) {
+ struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
+ struct enc_key *key;
+ uint16_t param_set_len = le16_to_cpu(keyparam->length);
+ uint16_t key_len = le16_to_cpu(keyparam->keylen);
+ uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
+ uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
+ void *end;
+
+ end = (void *)keyparam + sizeof(keyparam->type)
+ + sizeof(keyparam->length) + param_set_len;
+
+ /* Make sure we don't access past the end of the IEs */
+ if (end > resp_end)
+ break;
+
+ if (key_flags & KEY_INFO_WPA_UNICAST)
+ key = &priv->wpa_unicast_key;
+ else if (key_flags & KEY_INFO_WPA_MCAST)
+ key = &priv->wpa_mcast_key;
+ else
+ break;
- cmd->size = cpu_to_le16( S_DS_GEN
- + sizeof (pkeymaterial->action)
- + (index * sizeof(struct MrvlIEtype_keyParamSet)));
+ /* Copy returned key into driver */
+ memset(key, 0, sizeof(struct enc_key));
+ if (key_len > sizeof(key->key))
+ break;
+ key->type = key_type;
+ key->flags = key_flags;
+ key->len = key_len;
+ memcpy(key->key, keyparam->key, key->len);
- ret = 0;
+ buf_ptr = end + 1;
+ }
+ }
-done:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
command == CMD_802_11_AUTHENTICATE)
timeo = 10 * HZ;
- lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
+ lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
- lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
+ lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
/* Let the timer kick in and retry, and potentially reset
the whole thing if the condition persists */
timeo = HZ;
- } else
- lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n",
- command, jiffies);
+ }
/* Setup the timer after transmit command */
mod_timer(&priv->command_timer, jiffies + timeo);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
mac->action = cpu_to_le16(priv->currentpacketfilter);
- lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
+ lbs_deb_cmd("MAC_CONTROL: action 0x%04x, size %d\n",
le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
lbs_deb_leave(LBS_DEB_CMD);
ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
break;
- case CMD_802_11_SCAN:
- ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
- break;
-
case CMD_MAC_CONTROL:
ret = lbs_cmd_mac_control(priv, cmdptr);
break;
ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
break;
- case CMD_802_11_KEY_MATERIAL:
- ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
- cmd_oid, pdata_buf);
- break;
-
case CMD_802_11_PAIRWISE_TSC:
break;
case CMD_802_11_GROUP_TSC:
unsigned long flags;
int ret = 0;
- // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
- // only caller to us is lbs_thread() and we get even when a
- // data packet is received
+ /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+ * only caller to us is lbs_thread() and we get even when a
+ * data packet is received */
lbs_deb_enter(LBS_DEB_THREAD);
spin_lock_irqsave(&priv->driver_lock, flags);
struct cmd_header *buf = (void *)extra;
uint16_t copy_len;
- lbs_deb_enter(LBS_DEB_CMD);
-
copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
- lbs_deb_cmd("Copying back %u bytes; command response was %u bytes, "
- "copy back buffer was %u bytes\n", copy_len,
- le16_to_cpu(resp->size), le16_to_cpu(buf->size));
memcpy(buf, resp, copy_len);
-
- lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
struct assoc_request *assoc);
int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
uint16_t *enable);
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc);
#endif /* _LBS_CMD_H */
lbs_deb_cmd("disconnected, so exit PS mode\n");
lbs_ps_wakeup(priv, 0);
}
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_ASSOC);
}
/**
return 0;
}
-static int lbs_ret_802_11_key_material(struct lbs_private *priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_key_material *pkeymaterial =
- &resp->params.keymaterial;
- u16 action = le16_to_cpu(pkeymaterial->action);
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- /* Copy the returned key to driver private data */
- if (action == CMD_ACT_GET) {
- u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
- u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
-
- while (buf_ptr < resp_end) {
- struct MrvlIEtype_keyParamSet * pkeyparamset =
- (struct MrvlIEtype_keyParamSet *) buf_ptr;
- struct enc_key * pkey;
- u16 param_set_len = le16_to_cpu(pkeyparamset->length);
- u16 key_len = le16_to_cpu(pkeyparamset->keylen);
- u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
- u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
- u8 * end;
-
- end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
- + sizeof (pkeyparamset->length)
- + param_set_len;
- /* Make sure we don't access past the end of the IEs */
- if (end > resp_end)
- break;
-
- if (key_flags & KEY_INFO_WPA_UNICAST)
- pkey = &priv->wpa_unicast_key;
- else if (key_flags & KEY_INFO_WPA_MCAST)
- pkey = &priv->wpa_mcast_key;
- else
- break;
-
- /* Copy returned key into driver */
- memset(pkey, 0, sizeof(struct enc_key));
- if (key_len > sizeof(pkey->key))
- break;
- pkey->type = key_type;
- pkey->flags = key_flags;
- pkey->len = key_len;
- memcpy(pkey->key, pkeyparamset->key, pkey->len);
-
- buf_ptr = end + 1;
- }
- }
-
- lbs_deb_enter(LBS_DEB_CMD);
- return 0;
-}
-
static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
ret = lbs_ret_reg_access(priv, respcmd, resp);
break;
- case CMD_RET(CMD_802_11_SCAN):
- ret = lbs_ret_80211_scan(priv, resp);
- break;
-
case CMD_RET(CMD_802_11_GET_LOG):
ret = lbs_ret_get_log(priv, resp);
break;
ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
break;
- case CMD_RET(CMD_802_11_KEY_MATERIAL):
- ret = lbs_ret_802_11_key_material(priv, resp);
- break;
-
case CMD_RET(CMD_802_11_EEPROM_ACCESS):
ret = lbs_ret_802_11_eeprom_access(priv, resp);
break;
respcmd = le16_to_cpu(resp->command);
result = le16_to_cpu(resp->result);
- lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
+ lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
- lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
+ lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, priv->upld_len);
if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
return ret;
}
-static ssize_t lbs_extscan(struct file *file, const char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct lbs_private *priv = file->private_data;
- ssize_t res, buf_size;
- union iwreq_data wrqu;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
-
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- res = -EFAULT;
- goto out_unlock;
- }
-
- lbs_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
-
- memset(&wrqu, 0, sizeof(union iwreq_data));
- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
-
-out_unlock:
- free_page(addr);
- return count;
-}
-
-static void lbs_parse_bssid(char *buf, size_t count,
- struct lbs_ioctl_user_scan_cfg *scan_cfg)
-{
- char *hold;
- unsigned int mac[ETH_ALEN];
-
- hold = strstr(buf, "bssid=");
- if (!hold)
- return;
- hold += 6;
- sscanf(hold, "%02x:%02x:%02x:%02x:%02x:%02x",
- mac, mac+1, mac+2, mac+3, mac+4, mac+5);
- memcpy(scan_cfg->bssid, mac, ETH_ALEN);
-}
-
-static void lbs_parse_ssid(char *buf, size_t count,
- struct lbs_ioctl_user_scan_cfg *scan_cfg)
-{
- char *hold, *end;
- ssize_t size;
-
- hold = strstr(buf, "ssid=");
- if (!hold)
- return;
- hold += 5;
- end = strchr(hold, ' ');
- if (!end)
- end = buf + count - 1;
-
- size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold));
- strncpy(scan_cfg->ssid, hold, size);
-
- return;
-}
-
-static int lbs_parse_clear(char *buf, size_t count, const char *tag)
-{
- char *hold;
- int val;
-
- hold = strstr(buf, tag);
- if (!hold)
- return 0;
- hold += strlen(tag);
- sscanf(hold, "%d", &val);
-
- if (val != 0)
- val = 1;
-
- return val;
-}
-
-static int lbs_parse_dur(char *buf, size_t count,
- struct lbs_ioctl_user_scan_cfg *scan_cfg)
-{
- char *hold;
- int val;
-
- hold = strstr(buf, "dur=");
- if (!hold)
- return 0;
- hold += 4;
- sscanf(hold, "%d", &val);
-
- return val;
-}
-
-static void lbs_parse_type(char *buf, size_t count,
- struct lbs_ioctl_user_scan_cfg *scan_cfg)
-{
- char *hold;
- int val;
-
- hold = strstr(buf, "type=");
- if (!hold)
- return;
- hold += 5;
- sscanf(hold, "%d", &val);
-
- /* type=1,2 or 3 */
- if (val < 1 || val > 3)
- return;
-
- scan_cfg->bsstype = val;
-
- return;
-}
-
-static ssize_t lbs_setuserscan(struct file *file,
- const char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct lbs_private *priv = file->private_data;
- ssize_t res, buf_size;
- struct lbs_ioctl_user_scan_cfg *scan_cfg;
- union iwreq_data wrqu;
- int dur;
- char *buf = (char *)get_zeroed_page(GFP_KERNEL);
-
- if (!buf)
- return -ENOMEM;
-
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- res = -EFAULT;
- goto out_buf;
- }
-
- scan_cfg = kzalloc(sizeof(struct lbs_ioctl_user_scan_cfg), GFP_KERNEL);
- if (!scan_cfg) {
- res = -ENOMEM;
- goto out_buf;
- }
- res = count;
-
- scan_cfg->bsstype = LBS_SCAN_BSS_TYPE_ANY;
-
- dur = lbs_parse_dur(buf, count, scan_cfg);
- lbs_parse_bssid(buf, count, scan_cfg);
- scan_cfg->clear_bssid = lbs_parse_clear(buf, count, "clear_bssid=");
- lbs_parse_ssid(buf, count, scan_cfg);
- scan_cfg->clear_ssid = lbs_parse_clear(buf, count, "clear_ssid=");
- lbs_parse_type(buf, count, scan_cfg);
-
- lbs_scan_networks(priv, scan_cfg, 1);
- wait_event_interruptible(priv->cmd_pending,
- priv->surpriseremoved || !priv->last_scanned_channel);
-
- if (priv->surpriseremoved)
- goto out_scan_cfg;
-
- memset(&wrqu, 0x00, sizeof(union iwreq_data));
- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
-
- out_scan_cfg:
- kfree(scan_cfg);
- out_buf:
- free_page((unsigned long)buf);
- return res;
-}
-
-
/*
* When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
* get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
write_file_dummy), },
{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
lbs_sleepparams_write), },
- { "extscan", 0600, FOPS(NULL, lbs_extscan), },
- { "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), },
};
static struct lbs_debugfs_files debugfs_events_files[] = {
wait_queue_head_t waitq;
struct workqueue_struct *work_thread;
+ /** Scanning */
struct delayed_work scan_work;
struct delayed_work assoc_work;
struct work_struct sync_channel;
+ /* remember which channel was scanned last, != 0 if currently scanning */
+ int scan_channel;
+ u8 scan_ssid[IW_ESSID_MAX_SIZE + 1];
+ u8 scan_ssid_len;
/** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
struct cmd_ds_802_11_get_log logmsg;
u32 monitormode;
- int last_scanned_channel;
u8 fw_ready;
};
* Define data structure for CMD_802_11_SCAN
*/
struct cmd_ds_802_11_scan {
- u8 bsstype;
- u8 bssid[ETH_ALEN];
- u8 tlvbuffer[1];
+ struct cmd_header hdr;
+
+ uint8_t bsstype;
+ uint8_t bssid[ETH_ALEN];
+ uint8_t tlvbuffer[0];
#if 0
mrvlietypes_ssidparamset_t ssidParamSet;
mrvlietypes_chanlistparamset_t ChanListParamSet;
};
struct cmd_ds_802_11_scan_rsp {
+ struct cmd_header hdr;
+
__le16 bssdescriptsize;
- u8 nr_sets;
- u8 bssdesc_and_tlvbuffer[1];
+ uint8_t nr_sets;
+ uint8_t bssdesc_and_tlvbuffer[0];
};
struct cmd_ds_802_11_get_log {
} __attribute__ ((packed));
struct cmd_ds_802_11_key_material {
+ struct cmd_header hdr;
+
__le16 action;
struct MrvlIEtype_keyParamSet keyParamSet[2];
} __attribute__ ((packed));
/* command Body */
union {
struct cmd_ds_802_11_ps_mode psmode;
- struct cmd_ds_802_11_scan scan;
- struct cmd_ds_802_11_scan_rsp scanresp;
struct cmd_ds_mac_control macctrl;
struct cmd_ds_802_11_associate associate;
struct cmd_ds_802_11_deauthenticate deauth;
struct cmd_ds_802_11_rssi_rsp rssirsp;
struct cmd_ds_802_11_disassociate dassociate;
struct cmd_ds_802_11_mac_address macadd;
- struct cmd_ds_802_11_key_material keymaterial;
struct cmd_ds_mac_reg_access macreg;
struct cmd_ds_bbp_reg_access bbpreg;
struct cmd_ds_rf_reg_access rfreg;
}
/**
- * @brief Unsets the MSB on basic rates
- *
- * Scan through an array and unset the MSB for basic data rates.
- *
- * @param rates buffer of data rates
- * @param len size of buffer
- */
-void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- rates[i] &= 0x7f;
-}
-
-
-/**
* @brief Associate to a specific BSS discovered in a scan
*
* @param priv A pointer to struct lbs_private structure
priv->curbssparams.ssid_len = bss->ssid_len;
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
- lbs_deb_assoc("ASSOC_RESP: currentpacketfilter is 0x%x\n",
- priv->currentpacketfilter);
-
priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req);
-void lbs_unset_basic_rate_flags(u8 *rates, size_t len);
-
#endif
lbs_deb_leave(LBS_DEB_CMD);
}
+static void lbs_sync_channel_worker(struct work_struct *work)
+{
+ struct lbs_private *priv = container_of(work, struct lbs_private,
+ sync_channel);
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+ if (lbs_update_channel(priv))
+ lbs_pr_info("Channel synchronization failed.");
+ lbs_deb_leave(LBS_DEB_MAIN);
+}
+
+
static int lbs_init_adapter(struct lbs_private *priv)
{
size_t bufsize;
priv->work_thread = create_singlethread_workqueue("lbs_worker");
INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
- INIT_WORK(&priv->sync_channel, lbs_sync_channel);
+ INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
sprintf(priv->mesh_ssid, "mesh");
priv->mesh_ssid_len = 4;
#include "dev.h"
#include "scan.h"
#include "join.h"
+#include "cmd.h"
//! Approximate amount of data needed to pass a scan result back to iwlist
#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
//! Memory needed to store a max number/size SSID TLV for a firmware scan
#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset))
-//! Maximum memory needed for a lbs_scan_cmd_config with all TLVs at max
-#define MAX_SCAN_CFG_ALLOC (sizeof(struct lbs_scan_cmd_config) \
- + CHAN_TLV_MAX_SIZE \
- + SSID_TLV_MAX_SIZE)
+//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max
+#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \
+ + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE)
//! The maximum number of channels the firmware can scan per command
#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
//! Scan time specified in the channel TLV for each channel for active scans
#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
-static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-
-
+static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
+ struct cmd_header *resp);
/*********************************************************************/
/* */
/* */
/*********************************************************************/
-static inline void clear_bss_descriptor (struct bss_descriptor * bss)
+/**
+ * @brief Unsets the MSB on basic rates
+ *
+ * Scan through an array and unset the MSB for basic data rates.
+ *
+ * @param rates buffer of data rates
+ * @param len size of buffer
+ */
+static void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ rates[i] &= 0x7f;
+}
+
+
+static inline void clear_bss_descriptor(struct bss_descriptor *bss)
{
/* Don't blow away ->list, just BSS data */
memset(bss, 0, offsetof(struct bss_descriptor, list));
*
* @return 0: ssid is same, otherwise is different
*/
-int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
+int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2,
+ uint8_t ssid2_len)
{
if (ssid1_len != ssid2_len)
return -1;
}
static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
- struct bss_descriptor * match_bss)
+ struct bss_descriptor *match_bss)
{
- if ( !secinfo->wep_enabled
- && !secinfo->WPAenabled
+ if (!secinfo->wep_enabled && !secinfo->WPAenabled
&& !secinfo->WPA2enabled
&& match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
&& match_bss->rsn_ie[0] != MFIE_TYPE_RSN
- && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
- }
- return 0;
+ else
+ return 0;
}
static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
- struct bss_descriptor * match_bss)
+ struct bss_descriptor *match_bss)
{
- if ( secinfo->wep_enabled
- && !secinfo->WPAenabled
- && !secinfo->WPA2enabled
- && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ if (secinfo->wep_enabled && !secinfo->WPAenabled
+ && !secinfo->WPA2enabled
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
- }
- return 0;
+ else
+ return 0;
}
static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
- struct bss_descriptor * match_bss)
+ struct bss_descriptor *match_bss)
{
- if ( !secinfo->wep_enabled
- && secinfo->WPAenabled
- && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
- /* privacy bit may NOT be set in some APs like LinkSys WRT54G
- && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
- */
- ) {
+ if (!secinfo->wep_enabled && secinfo->WPAenabled
+ && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
+ /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
+ )
return 1;
- }
- return 0;
+ else
+ return 0;
}
static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
- struct bss_descriptor * match_bss)
+ struct bss_descriptor *match_bss)
{
- if ( !secinfo->wep_enabled
- && secinfo->WPA2enabled
- && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
- /* privacy bit may NOT be set in some APs like LinkSys WRT54G
- && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
- */
- ) {
+ if (!secinfo->wep_enabled && secinfo->WPA2enabled
+ && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
+ /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
+ )
return 1;
- }
- return 0;
+ else
+ return 0;
}
static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
- struct bss_descriptor * match_bss)
+ struct bss_descriptor *match_bss)
{
- if ( !secinfo->wep_enabled
- && !secinfo->WPAenabled
- && !secinfo->WPA2enabled
- && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
- && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
- && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ if (!secinfo->wep_enabled && !secinfo->WPAenabled
+ && !secinfo->WPA2enabled
+ && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
+ && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
- }
- return 0;
+ else
+ return 0;
}
static inline int is_same_network(struct bss_descriptor *src,
* @return Index in scantable, or error code if negative
*/
static int is_network_compatible(struct lbs_private *priv,
- struct bss_descriptor * bss, u8 mode)
+ struct bss_descriptor *bss, uint8_t mode)
{
int matched = 0;
} else if ((matched = match_bss_static_wep(&priv->secinfo, bss))) {
goto done;
} else if ((matched = match_bss_wpa(&priv->secinfo, bss))) {
- lbs_deb_scan(
- "is_network_compatible() WPA: wpa_ie 0x%x "
- "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
- "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
- priv->secinfo.wep_enabled ? "e" : "d",
- priv->secinfo.WPAenabled ? "e" : "d",
- priv->secinfo.WPA2enabled ? "e" : "d",
- (bss->capability & WLAN_CAPABILITY_PRIVACY));
+ lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x "
+ "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
+ "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+ priv->secinfo.wep_enabled ? "e" : "d",
+ priv->secinfo.WPAenabled ? "e" : "d",
+ priv->secinfo.WPA2enabled ? "e" : "d",
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
} else if ((matched = match_bss_wpa2(&priv->secinfo, bss))) {
- lbs_deb_scan(
- "is_network_compatible() WPA2: wpa_ie 0x%x "
- "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
- "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
- priv->secinfo.wep_enabled ? "e" : "d",
- priv->secinfo.WPAenabled ? "e" : "d",
- priv->secinfo.WPA2enabled ? "e" : "d",
- (bss->capability & WLAN_CAPABILITY_PRIVACY));
+ lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x "
+ "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
+ "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+ priv->secinfo.wep_enabled ? "e" : "d",
+ priv->secinfo.WPAenabled ? "e" : "d",
+ priv->secinfo.WPA2enabled ? "e" : "d",
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
} else if ((matched = match_bss_dynamic_wep(&priv->secinfo, bss))) {
- lbs_deb_scan(
- "is_network_compatible() dynamic WEP: "
- "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
- bss->wpa_ie[0], bss->rsn_ie[0],
- (bss->capability & WLAN_CAPABILITY_PRIVACY));
+ lbs_deb_scan("is_network_compatible() dynamic WEP: "
+ "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
+ bss->wpa_ie[0], bss->rsn_ie[0],
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
}
/* bss security settings don't match those configured on card */
- lbs_deb_scan(
- "is_network_compatible() FAILED: wpa_ie 0x%x "
- "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
- bss->wpa_ie[0], bss->rsn_ie[0],
- priv->secinfo.wep_enabled ? "e" : "d",
- priv->secinfo.WPAenabled ? "e" : "d",
- priv->secinfo.WPA2enabled ? "e" : "d",
- (bss->capability & WLAN_CAPABILITY_PRIVACY));
+ lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x "
+ "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
+ bss->wpa_ie[0], bss->rsn_ie[0],
+ priv->secinfo.wep_enabled ? "e" : "d",
+ priv->secinfo.WPAenabled ? "e" : "d",
+ priv->secinfo.WPA2enabled ? "e" : "d",
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
done:
lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
-
/*********************************************************************/
/* */
/* Main scanning support */
/* */
/*********************************************************************/
-void lbs_scan_worker(struct work_struct *work)
-{
- struct lbs_private *priv =
- container_of(work, struct lbs_private, scan_work.work);
-
- lbs_deb_enter(LBS_DEB_SCAN);
- lbs_scan_networks(priv, NULL, 0);
- lbs_deb_leave(LBS_DEB_SCAN);
-}
-
-
/**
* @brief Create a channel list for the driver to scan based on region info
*
*
* @param priv A pointer to struct lbs_private structure
* @param scanchanlist Output parameter: resulting channel list to scan
- * @param filteredscan Flag indicating whether or not a BSSID or SSID filter
- * is being sent in the command to firmware. Used to
- * increase the number of channels sent in a scan
- * command and to disable the firmware channel scan
- * filter.
*
* @return void
*/
static int lbs_scan_create_channel_list(struct lbs_private *priv,
- struct chanscanparamset * scanchanlist,
- u8 filteredscan)
+ struct chanscanparamset *scanchanlist)
{
-
struct region_channel *scanregion;
struct chan_freq_power *cfp;
int rgnidx;
int chanidx;
int nextchan;
- u8 scantype;
+ uint8_t scantype;
chanidx = 0;
scantype = CMD_SCAN_TYPE_ACTIVE;
for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
- if (priv->enable11d &&
- (priv->connect_status != LBS_CONNECTED) &&
- (priv->mesh_connect_status != LBS_CONNECTED)) {
+ if (priv->enable11d && (priv->connect_status != LBS_CONNECTED)
+ && (priv->mesh_connect_status != LBS_CONNECTED)) {
/* Scan all the supported chan for the first scan */
if (!priv->universal_channel[rgnidx].valid)
continue;
scanregion = &priv->region_channel[rgnidx];
}
- for (nextchan = 0;
- nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
+ for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
+ struct chanscanparamset *chan = &scanchanlist[chanidx];
cfp = scanregion->CFP + nextchan;
- if (priv->enable11d) {
- scantype =
- lbs_get_scan_type_11d(cfp->channel,
- &priv->
- parsed_region_chan);
- }
+ if (priv->enable11d)
+ scantype = lbs_get_scan_type_11d(cfp->channel,
+ &priv->parsed_region_chan);
- switch (scanregion->band) {
- case BAND_B:
- case BAND_G:
- default:
- scanchanlist[chanidx].radiotype =
- CMD_SCAN_RADIO_TYPE_BG;
- break;
- }
+ if (scanregion->band == BAND_B || scanregion->band == BAND_G)
+ chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
if (scantype == CMD_SCAN_TYPE_PASSIVE) {
- scanchanlist[chanidx].maxscantime =
- cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
- scanchanlist[chanidx].chanscanmode.passivescan =
- 1;
+ chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
+ chan->chanscanmode.passivescan = 1;
} else {
- scanchanlist[chanidx].maxscantime =
- cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME);
- scanchanlist[chanidx].chanscanmode.passivescan =
- 0;
+ chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME);
+ chan->chanscanmode.passivescan = 0;
}
- scanchanlist[chanidx].channumber = cfp->channel;
-
- if (filteredscan) {
- scanchanlist[chanidx].chanscanmode.
- disablechanfilt = 1;
- }
+ chan->channumber = cfp->channel;
}
}
return chanidx;
* length 06 00
* ssid 4d 4e 54 45 53 54
*/
-static int lbs_scan_add_ssid_tlv(u8 *tlv,
- const struct lbs_ioctl_user_scan_cfg *user_cfg)
+static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
{
- struct mrvlietypes_ssidparamset *ssid_tlv =
- (struct mrvlietypes_ssidparamset *)tlv;
+ struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv;
+
ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
- ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len);
- memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len);
- return sizeof(ssid_tlv->header) + user_cfg->ssid_len;
+ ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
+ memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len);
+ return sizeof(ssid_tlv->header) + priv->scan_ssid_len;
}
* channel 13 00 0d 00 00 00 64 00
*
*/
-static int lbs_scan_add_chanlist_tlv(u8 *tlv,
- struct chanscanparamset *chan_list,
- int chan_count)
+static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
+ struct chanscanparamset *chan_list,
+ int chan_count)
{
- size_t size = sizeof(struct chanscanparamset) * chan_count;
- struct mrvlietypes_chanlistparamset *chan_tlv =
- (struct mrvlietypes_chanlistparamset *) tlv;
+ size_t size = sizeof(struct chanscanparamset) *chan_count;
+ struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv;
chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
memcpy(chan_tlv->chanscanparam, chan_list, size);
* The rates are in lbs_bg_rates[], but for the 802.11b
* rates the high bit isn't set.
*/
-static int lbs_scan_add_rates_tlv(u8 *tlv)
+static int lbs_scan_add_rates_tlv(uint8_t *tlv)
{
int i;
- struct mrvlietypes_ratesparamset *rate_tlv =
- (struct mrvlietypes_ratesparamset *) tlv;
+ struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv;
rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
tlv += sizeof(rate_tlv->header);
* Generate the CMD_802_11_SCAN command with the proper tlv
* for a bunch of channels.
*/
-static int lbs_do_scan(struct lbs_private *priv,
- u8 bsstype,
- struct chanscanparamset *chan_list,
- int chan_count,
- const struct lbs_ioctl_user_scan_cfg *user_cfg)
+static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype,
+ struct chanscanparamset *chan_list, int chan_count)
{
int ret = -ENOMEM;
- struct lbs_scan_cmd_config *scan_cmd;
- u8 *tlv; /* pointer into our current, growing TLV storage area */
+ struct cmd_ds_802_11_scan *scan_cmd;
+ uint8_t *tlv; /* pointer into our current, growing TLV storage area */
- lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, "
- "chan_count %d",
- bsstype, chan_list[0].channumber, chan_count);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d",
+ bsstype, chan_list[0].channumber, chan_count);
/* create the fixed part for scan command */
scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
if (scan_cmd == NULL)
goto out;
+
tlv = scan_cmd->tlvbuffer;
- if (user_cfg)
- memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN);
+ /* TODO: do we need to scan for a specific BSSID?
+ memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */
scan_cmd->bsstype = bsstype;
/* add TLVs */
- if (user_cfg && user_cfg->ssid_len)
- tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg);
+ if (priv->scan_ssid_len)
+ tlv += lbs_scan_add_ssid_tlv(priv, tlv);
if (chan_list && chan_count)
tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
tlv += lbs_scan_add_rates_tlv(tlv);
/* This is the final data we are about to send */
- scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer;
- lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6);
+ scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd);
+ lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
+ sizeof(*scan_cmd));
lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
- scan_cmd->tlvbufferlen);
+ tlv - scan_cmd->tlvbuffer);
+
+ ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
+ le16_to_cpu(scan_cmd->hdr.size),
+ lbs_ret_80211_scan, 0);
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
- CMD_OPTION_WAITFORRSP, 0, scan_cmd);
out:
kfree(scan_cmd);
lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
* update the internal driver scan table
*
* @param priv A pointer to struct lbs_private structure
- * @param puserscanin Pointer to the input configuration for the requested
- * scan.
+ * @param full_scan Do a full-scan (blocking)
*
* @return 0 or < 0 if error
*/
-int lbs_scan_networks(struct lbs_private *priv,
- const struct lbs_ioctl_user_scan_cfg *user_cfg,
- int full_scan)
+static int lbs_scan_networks(struct lbs_private *priv, int full_scan)
{
int ret = -ENOMEM;
struct chanscanparamset *chan_list;
struct chanscanparamset *curr_chans;
int chan_count;
- u8 bsstype = CMD_BSS_TYPE_ANY;
+ uint8_t bsstype = CMD_BSS_TYPE_ANY;
int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
- int filteredscan = 0;
union iwreq_data wrqu;
#ifdef CONFIG_LIBERTAS_DEBUG
struct bss_descriptor *iter;
DECLARE_MAC_BUF(mac);
#endif
- lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d",
- full_scan);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
/* Cancel any partial outstanding partial scans if this scan
* is a full scan.
if (full_scan && delayed_work_pending(&priv->scan_work))
cancel_delayed_work(&priv->scan_work);
- /* Determine same scan parameters */
+ /* User-specified bsstype or channel list
+ TODO: this can be implemented if some user-space application
+ need the feature. Formerly, it was accessible from debugfs,
+ but then nowhere used.
if (user_cfg) {
if (user_cfg->bsstype)
- bsstype = user_cfg->bsstype;
- if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) {
- numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN;
- filteredscan = 1;
- }
- }
- lbs_deb_scan("numchannels %d, bsstype %d, "
- "filteredscan %d\n",
- numchannels, bsstype, filteredscan);
+ bsstype = user_cfg->bsstype;
+ } */
+
+ lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype);
/* Create list of channels to scan */
chan_list = kzalloc(sizeof(struct chanscanparamset) *
- LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+ LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
if (!chan_list) {
lbs_pr_alert("SCAN: chan_list empty\n");
goto out;
}
/* We want to scan all channels */
- chan_count = lbs_scan_create_channel_list(priv, chan_list,
- filteredscan);
+ chan_count = lbs_scan_create_channel_list(priv, chan_list);
netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev);
}
/* Prepare to continue an interrupted scan */
- lbs_deb_scan("chan_count %d, last_scanned_channel %d\n",
- chan_count, priv->last_scanned_channel);
+ lbs_deb_scan("chan_count %d, scan_channel %d\n",
+ chan_count, priv->scan_channel);
curr_chans = chan_list;
/* advance channel list by already-scanned-channels */
- if (priv->last_scanned_channel > 0) {
- curr_chans += priv->last_scanned_channel;
- chan_count -= priv->last_scanned_channel;
+ if (priv->scan_channel > 0) {
+ curr_chans += priv->scan_channel;
+ chan_count -= priv->scan_channel;
}
/* Send scan command(s)
while (chan_count) {
int to_scan = min(numchannels, chan_count);
lbs_deb_scan("scanning %d of %d channels\n",
- to_scan, chan_count);
+ to_scan, chan_count);
ret = lbs_do_scan(priv, bsstype, curr_chans,
- to_scan, user_cfg);
+ to_scan);
if (ret) {
lbs_pr_err("SCAN_CMD failed\n");
goto out2;
chan_count -= to_scan;
/* somehow schedule the next part of the scan */
- if (chan_count &&
- !full_scan &&
+ if (chan_count && !full_scan &&
!priv->surpriseremoved) {
/* -1 marks just that we're currently scanning */
- if (priv->last_scanned_channel < 0)
- priv->last_scanned_channel = to_scan;
+ if (priv->scan_channel < 0)
+ priv->scan_channel = to_scan;
else
- priv->last_scanned_channel += to_scan;
+ priv->scan_channel += to_scan;
cancel_delayed_work(&priv->scan_work);
queue_delayed_work(priv->work_thread, &priv->scan_work,
- msecs_to_jiffies(300));
+ msecs_to_jiffies(300));
/* skip over GIWSCAN event */
goto out;
}
lbs_deb_scan("scan table:\n");
list_for_each_entry(iter, &priv->network_list, list)
lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n",
- i++, print_mac(mac, iter->bssid), (s32) iter->rssi,
- escape_essid(iter->ssid, iter->ssid_len));
+ i++, print_mac(mac, iter->bssid), (int)iter->rssi,
+ escape_essid(iter->ssid, iter->ssid_len));
mutex_unlock(&priv->lock);
#endif
out2:
- priv->last_scanned_channel = 0;
+ priv->scan_channel = 0;
out:
if (priv->connect_status == LBS_CONNECTED) {
+void lbs_scan_worker(struct work_struct *work)
+{
+ struct lbs_private *priv =
+ container_of(work, struct lbs_private, scan_work.work);
+
+ lbs_deb_enter(LBS_DEB_SCAN);
+ lbs_scan_networks(priv, 0);
+ lbs_deb_leave(LBS_DEB_SCAN);
+}
+
+
/*********************************************************************/
/* */
/* Result interpretation */
* @return 0 or -1
*/
static int lbs_process_bss(struct bss_descriptor *bss,
- u8 ** pbeaconinfo, int *bytesleft)
+ uint8_t **pbeaconinfo, int *bytesleft)
{
struct ieeetypes_fhparamset *pFH;
struct ieeetypes_dsparamset *pDS;
struct ieeetypes_ibssparamset *pibss;
DECLARE_MAC_BUF(mac);
struct ieeetypes_countryinfoset *pcountryinfo;
- u8 *pos, *end, *p;
- u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
- u16 beaconsize = 0;
+ uint8_t *pos, *end, *p;
+ uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
+ uint16_t beaconsize = 0;
int ret;
lbs_deb_enter(LBS_DEB_SCAN);
/* process variable IE */
while (pos <= end - 2) {
- struct ieee80211_info_element * elem =
- (struct ieee80211_info_element *) pos;
+ struct ieee80211_info_element * elem = (void *)pos;
if (pos + elem->len > end) {
lbs_deb_scan("process_bss: error in processing IE, "
- "bytes left < IE length\n");
+ "bytes left < IE length\n");
break;
}
break;
case MFIE_TYPE_RATES:
- n_basic_rates = min_t(u8, MAX_RATES, elem->len);
+ n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len);
memcpy(bss->rates, elem->data, n_basic_rates);
got_basic_rates = 1;
lbs_deb_scan("got RATES IE\n");
lbs_deb_scan("got COUNTRY IE\n");
if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
|| pcountryinfo->len > 254) {
- lbs_deb_scan("process_bss: 11D- Err "
- "CountryInfo len %d, min %zd, max 254\n",
- pcountryinfo->len,
- sizeof(pcountryinfo->countrycode));
+ lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n",
+ pcountryinfo->len, sizeof(pcountryinfo->countrycode));
ret = -1;
goto done;
}
- memcpy(&bss->countryinfo,
- pcountryinfo, pcountryinfo->len + 2);
+ memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2);
lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
- (u8 *) pcountryinfo,
- (u32) (pcountryinfo->len + 2));
+ (uint8_t *) pcountryinfo,
+ (int) (pcountryinfo->len + 2));
break;
case MFIE_TYPE_RATES_EX:
case MFIE_TYPE_GENERIC:
if (elem->len >= 4 &&
- elem->data[0] == 0x00 &&
- elem->data[1] == 0x50 &&
- elem->data[2] == 0xf2 &&
- elem->data[3] == 0x01) {
- bss->wpa_ie_len = min(elem->len + 2,
- MAX_WPA_IE_LEN);
+ elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
+ elem->data[2] == 0xf2 && elem->data[3] == 0x01) {
+ bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
lbs_deb_scan("got WPA IE\n");
- lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
- elem->len);
+ lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len);
} else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
- elem->data[0] == 0x00 &&
- elem->data[1] == 0x50 &&
- elem->data[2] == 0x43 &&
- elem->data[3] == 0x04) {
+ elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
+ elem->data[2] == 0x43 && elem->data[3] == 0x04) {
lbs_deb_scan("got mesh IE\n");
bss->mesh = 1;
} else {
- lbs_deb_scan("got generiec IE: "
- "%02x:%02x:%02x:%02x, len %d\n",
+ lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
elem->data[0], elem->data[1],
elem->data[2], elem->data[3],
elem->len);
bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
- bss->rsn_ie, elem->len);
+ bss->rsn_ie, elem->len);
break;
default:
lbs_deb_scan("got IE 0x%04x, len %d\n",
- elem->id, elem->len);
+ elem->id, elem->len);
break;
}
* @return index in BSSID list, or error return code (< 0)
*/
struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
- u8 * bssid, u8 mode)
+ uint8_t *bssid, uint8_t mode)
{
- struct bss_descriptor * iter_bss;
- struct bss_descriptor * found_bss = NULL;
+ struct bss_descriptor *iter_bss;
+ struct bss_descriptor *found_bss = NULL;
lbs_deb_enter(LBS_DEB_SCAN);
if (!bssid)
goto out;
- lbs_deb_hex(LBS_DEB_SCAN, "looking for",
- bssid, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN);
/* Look through the scan table for a compatible match. The loop will
* continue past a matched bssid that is not compatible in case there
* @return index in BSSID list
*/
struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
- u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode,
- int channel)
+ uint8_t *ssid, uint8_t ssid_len,
+ uint8_t *bssid, uint8_t mode,
+ int channel)
{
- u8 bestrssi = 0;
+ uint8_t bestrssi = 0;
struct bss_descriptor * iter_bss = NULL;
struct bss_descriptor * found_bss = NULL;
struct bss_descriptor * tmp_oldest = NULL;
tmp_oldest = iter_bss;
if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
- ssid, ssid_len) != 0)
+ ssid, ssid_len) != 0)
continue; /* ssid doesn't match */
if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
continue; /* bssid doesn't match */
*
* @return index in BSSID list
*/
-static struct bss_descriptor *lbs_find_best_ssid_in_list(
- struct lbs_private *priv,
- u8 mode)
+static struct bss_descriptor *lbs_find_best_ssid_in_list(struct lbs_private *priv,
+ uint8_t mode)
{
- u8 bestrssi = 0;
- struct bss_descriptor * iter_bss;
- struct bss_descriptor * best_bss = NULL;
+ uint8_t bestrssi = 0;
+ struct bss_descriptor *iter_bss;
+ struct bss_descriptor *best_bss = NULL;
lbs_deb_enter(LBS_DEB_SCAN);
}
/**
- * @brief Find the AP with specific ssid in the scan list
+ * @brief Find the best AP
*
* Used from association worker.
*
*
* @return 0--success, otherwise--fail
*/
-int lbs_find_best_network_ssid(struct lbs_private *priv,
- u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode)
+int lbs_find_best_network_ssid(struct lbs_private *priv, uint8_t *out_ssid,
+ uint8_t *out_ssid_len, uint8_t preferred_mode,
+ uint8_t *out_mode)
{
int ret = -1;
- struct bss_descriptor * found;
+ struct bss_descriptor *found;
lbs_deb_enter(LBS_DEB_SCAN);
- lbs_scan_networks(priv, NULL, 1);
+ priv->scan_ssid_len = 0;
+ lbs_scan_networks(priv, 1);
if (priv->surpriseremoved)
goto out;
* @param priv A pointer to struct lbs_private structure
* @param ssid A pointer to the SSID to scan for
* @param ssid_len Length of the SSID
- * @param clear_ssid Should existing scan results with this SSID
- * be cleared?
*
* @return 0-success, otherwise fail
*/
-int lbs_send_specific_ssid_scan(struct lbs_private *priv,
- u8 *ssid, u8 ssid_len, u8 clear_ssid)
+int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,
+ uint8_t ssid_len)
{
- struct lbs_ioctl_user_scan_cfg scancfg;
int ret = 0;
- lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d",
- escape_essid(ssid, ssid_len), clear_ssid);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n",
+ escape_essid(ssid, ssid_len));
if (!ssid_len)
goto out;
- memset(&scancfg, 0x00, sizeof(scancfg));
- memcpy(scancfg.ssid, ssid, ssid_len);
- scancfg.ssid_len = ssid_len;
- scancfg.clear_ssid = clear_ssid;
+ memcpy(priv->scan_ssid, ssid, ssid_len);
+ priv->scan_ssid_len = ssid_len;
- lbs_scan_networks(priv, &scancfg, 1);
+ lbs_scan_networks(priv, 1);
if (priv->surpriseremoved) {
ret = -1;
goto out;
#define MAX_CUSTOM_LEN 64
static inline char *lbs_translate_scan(struct lbs_private *priv,
- char *start, char *stop,
- struct bss_descriptor *bss)
+ char *start, char *stop,
+ struct bss_descriptor *bss)
{
struct chan_freq_power *cfp;
char *current_val; /* For rates */
struct iw_event iwe; /* Temporary buffer */
int j;
-#define PERFECT_RSSI ((u8)50)
-#define WORST_RSSI ((u8)0)
-#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
- u8 rssi;
+#define PERFECT_RSSI ((uint8_t)50)
+#define WORST_RSSI ((uint8_t)0)
+#define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI))
+ uint8_t rssi;
lbs_deb_enter(LBS_DEB_SCAN);
/* SSID */
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
- iwe.u.data.length = min((u32) bss->ssid_len, (u32) IW_ESSID_MAX_SIZE);
+ iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
/* Mode */
rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
iwe.u.qual.qual =
- (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
- (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
- (RSSI_DIFF * RSSI_DIFF);
+ (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
+ (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
+ (RSSI_DIFF * RSSI_DIFF);
if (iwe.u.qual.qual > 100)
iwe.u.qual.qual = 100;
if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
} else {
- iwe.u.qual.noise =
- CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
+ iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
}
/* Locally created ad-hoc BSSs won't have beacons if this is the
* only station in the adhoc network; so get signal strength
* from receive statistics.
*/
- if ((priv->mode == IW_MODE_ADHOC)
- && priv->adhoccreate
+ if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate
&& !lbs_ssid_cmp(priv->curbssparams.ssid,
- priv->curbssparams.ssid_len,
- bss->ssid, bss->ssid_len)) {
+ priv->curbssparams.ssid_len,
+ bss->ssid, bss->ssid_len)) {
int snr, nf;
snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
current_val = iwe_stream_add_value(start, current_val,
stop, &iwe, IW_EV_PARAM_LEN);
}
- if ((bss->mode == IW_MODE_ADHOC)
+ if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
&& !lbs_ssid_cmp(priv->curbssparams.ssid,
- priv->curbssparams.ssid_len,
- bss->ssid, bss->ssid_len)
- && priv->adhoccreate) {
+ priv->curbssparams.ssid_len,
+ bss->ssid, bss->ssid_len)) {
iwe.u.bitrate.value = 22 * 500000;
current_val = iwe_stream_add_value(start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
+ stop, &iwe, IW_EV_PARAM_LEN);
}
/* Check if we added any event */
if((current_val - start) > IW_EV_LCP_LEN)
char *p = custom;
iwe.cmd = IWEVCUSTOM;
- p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
- "mesh-type: olpc");
+ p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
start = iwe_stream_add_point(start, stop, &iwe, custom);
* @return 0 --success, otherwise fail
*/
int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *wrqu, char *extra)
+ union iwreq_data *wrqu, char *extra)
{
struct lbs_private *priv = dev->priv;
+ int ret = 0;
- lbs_deb_enter(LBS_DEB_SCAN);
+ lbs_deb_enter(LBS_DEB_WEXT);
- if (!netif_running(dev))
- return -ENETDOWN;
+ if (!netif_running(dev)) {
+ ret = -ENETDOWN;
+ goto out;
+ }
/* mac80211 does this:
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->type != IEEE80211_IF_TYPE_xxx)
- return -EOPNOTSUPP;
+ if (sdata->type != IEEE80211_IF_TYPE_xxx) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+ */
if (wrqu->data.length == sizeof(struct iw_scan_req) &&
wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- req = (struct iw_scan_req *)extra;
- ssid = req->essid;
- ssid_len = req->essid_len;
+ struct iw_scan_req *req = (struct iw_scan_req *)extra;
+ priv->scan_ssid_len = req->essid_len;
+ memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);
+ lbs_deb_wext("set_scan, essid '%s'\n",
+ escape_essid(priv->scan_ssid, priv->scan_ssid_len));
+ } else {
+ priv->scan_ssid_len = 0;
}
- */
if (!delayed_work_pending(&priv->scan_work))
queue_delayed_work(priv->work_thread, &priv->scan_work,
- msecs_to_jiffies(50));
+ msecs_to_jiffies(50));
/* set marker that currently a scan is taking place */
- priv->last_scanned_channel = -1;
+ priv->scan_channel = -1;
if (priv->surpriseremoved)
- return -EIO;
+ ret = -EIO;
- lbs_deb_leave(LBS_DEB_SCAN);
- return 0;
+out:
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
}
* @return 0 --success, otherwise fail
*/
int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
+ struct iw_point *dwrq, char *extra)
{
#define SCAN_ITEM_SIZE 128
struct lbs_private *priv = dev->priv;
int err = 0;
char *ev = extra;
char *stop = ev + dwrq->length;
- struct bss_descriptor * iter_bss;
- struct bss_descriptor * safe;
+ struct bss_descriptor *iter_bss;
+ struct bss_descriptor *safe;
- lbs_deb_enter(LBS_DEB_SCAN);
+ lbs_deb_enter(LBS_DEB_WEXT);
/* iwlist should wait until the current scan is finished */
- if (priv->last_scanned_channel)
+ if (priv->scan_channel)
return -EAGAIN;
/* Update RSSI if current BSS is a locally created ad-hoc BSS */
- if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
+ if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate)
lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- CMD_OPTION_WAITFORRSP, 0, NULL);
- }
+ CMD_OPTION_WAITFORRSP, 0, NULL);
mutex_lock(&priv->lock);
list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
- char * next_ev;
+ char *next_ev;
unsigned long stale_time;
if (stop - ev < SCAN_ITEM_SIZE) {
/* Prune old an old scan result */
stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
if (time_after(jiffies, stale_time)) {
- list_move_tail (&iter_bss->list,
- &priv->network_free_list);
+ list_move_tail(&iter_bss->list, &priv->network_free_list);
clear_bss_descriptor(iter_bss);
continue;
}
dwrq->length = (ev - extra);
dwrq->flags = 0;
- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err);
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
return err;
}
/**
- * @brief Prepare a scan command to be sent to the firmware
- *
- * Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...)
- * from cmd.c
- *
- * Sends a fixed length data part (specifying the BSS type and BSSID filters)
- * as well as a variable number/length of TLVs to the firmware.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param cmd A pointer to cmd_ds_command structure to be sent to
- * firmware with the cmd_DS_801_11_SCAN structure
- * @param pdata_buf Void pointer cast of a lbs_scan_cmd_config struct used
- * to set the fields/TLVs for the command sent to firmware
- *
- * @return 0 or -1
- */
-int lbs_cmd_80211_scan(struct lbs_private *priv,
- struct cmd_ds_command *cmd, void *pdata_buf)
-{
- struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
- struct lbs_scan_cmd_config *pscancfg = pdata_buf;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- /* Set fixed field variables in scan command */
- pscan->bsstype = pscancfg->bsstype;
- memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
- memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
-
- /* size is equal to the sizeof(fixed portions) + the TLV len + header */
- cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
- + pscancfg->tlvbufferlen + S_DS_GEN);
-
- lbs_deb_leave(LBS_DEB_SCAN);
- return 0;
-}
-
-/**
* @brief This function handles the command response of scan
*
* Called from handle_cmd_response() in cmdrespc.
*
* @return 0 or -1
*/
-int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp)
+static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
+ struct cmd_header *resp)
{
- struct cmd_ds_802_11_scan_rsp *pscan;
- struct bss_descriptor * iter_bss;
- struct bss_descriptor * safe;
- u8 *pbssinfo;
- u16 scanrespsize;
+ struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
+ struct bss_descriptor *iter_bss;
+ struct bss_descriptor *safe;
+ uint8_t *bssinfo;
+ uint16_t scanrespsize;
int bytesleft;
int idx;
int tlvbufsize;
clear_bss_descriptor(iter_bss);
}
- pscan = &resp->params.scanresp;
-
- if (pscan->nr_sets > MAX_NETWORK_COUNT) {
- lbs_deb_scan(
- "SCAN_RESP: too many scan results (%d, max %d)!!\n",
- pscan->nr_sets, MAX_NETWORK_COUNT);
+ if (scanresp->nr_sets > MAX_NETWORK_COUNT) {
+ lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n",
+ scanresp->nr_sets, MAX_NETWORK_COUNT);
ret = -1;
goto done;
}
- bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+ bytesleft = le16_to_cpu(scanresp->bssdescriptsize);
lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
scanrespsize = le16_to_cpu(resp->size);
- lbs_deb_scan("SCAN_RESP: scan results %d\n", pscan->nr_sets);
+ lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets);
- pbssinfo = pscan->bssdesc_and_tlvbuffer;
+ bssinfo = scanresp->bssdesc_and_tlvbuffer;
/* The size of the TLV buffer is equal to the entire command response
* size (scanrespsize) minus the fixed fields (sizeof()'s), the
* BSS Descriptions (bssdescriptsize as bytesLef) and the command
* response header (S_DS_GEN)
*/
- tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize)
- + sizeof(pscan->nr_sets)
+ tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
+ + sizeof(scanresp->nr_sets)
+ S_DS_GEN);
/*
- * Process each scan response returned (pscan->nr_sets). Save
+ * Process each scan response returned (scanresp->nr_sets). Save
* the information in the newbssentry and then insert into the
* driver scan table either as an update to an existing entry
* or as an addition at the end of the table
*/
- for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) {
+ for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) {
struct bss_descriptor new;
- struct bss_descriptor * found = NULL;
- struct bss_descriptor * oldest = NULL;
+ struct bss_descriptor *found = NULL;
+ struct bss_descriptor *oldest = NULL;
DECLARE_MAC_BUF(mac);
/* Process the data fields and IEs returned for this BSS */
memset(&new, 0, sizeof (struct bss_descriptor));
- if (lbs_process_bss(&new, &pbssinfo, &bytesleft) != 0) {
+ if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) {
/* error parsing the scan response, skipped */
lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");
continue;
continue;
}
- lbs_deb_scan("SCAN_RESP: BSSID %s\n",
- print_mac(mac, new.bssid));
+ lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid));
/* Copy the locally created newbssentry to the scan table */
memcpy(found, &new, offsetof(struct bss_descriptor, list));
/**
* @brief Maximum number of channels that can be sent in a setuserscan ioctl
- *
- * @sa lbs_ioctl_user_scan_cfg
*/
#define LBS_IOCTL_USER_SCAN_CHAN_MAX 50
-//! Infrastructure BSS scan type in lbs_scan_cmd_config
+//! Infrastructure BSS scan type in cmd_ds_802_11_scan
#define LBS_SCAN_BSS_TYPE_BSS 1
-//! Adhoc BSS scan type in lbs_scan_cmd_config
+//! Adhoc BSS scan type in cmd_ds_802_11_scan
#define LBS_SCAN_BSS_TYPE_IBSS 2
-//! Adhoc or Infrastructure BSS scan type in lbs_scan_cmd_config, no filter
+//! Adhoc or Infrastructure BSS scan type in cmd_ds_802_11_scan, no filter
#define LBS_SCAN_BSS_TYPE_ANY 3
/**
- * @brief Structure used internally in the wlan driver to configure a scan.
- *
- * Sent to the command processing module to configure the firmware
- * scan command prepared by lbs_cmd_80211_scan.
- *
- * @sa lbs_scan_networks
- *
- */
-struct lbs_scan_cmd_config {
- /**
- * @brief BSS type to be sent in the firmware command
- *
- * Field can be used to restrict the types of networks returned in the
- * scan. valid settings are:
- *
- * - LBS_SCAN_BSS_TYPE_BSS (infrastructure)
- * - LBS_SCAN_BSS_TYPE_IBSS (adhoc)
- * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
- */
- u8 bsstype;
-
- /**
- * @brief Specific BSSID used to filter scan results in the firmware
- */
- u8 bssid[ETH_ALEN];
-
- /**
- * @brief length of TLVs sent in command starting at tlvBuffer
- */
- int tlvbufferlen;
-
- /**
- * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
- *
- * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t
- * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t
- */
- u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here
-};
-
-/**
- * @brief IOCTL channel sub-structure sent in lbs_ioctl_user_scan_cfg
- *
- * Multiple instances of this structure are included in the IOCTL command
- * to configure a instance of a scan on the specific channel.
- */
-struct lbs_ioctl_user_scan_chan {
- u8 channumber; //!< channel Number to scan
- u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1
- u8 scantype; //!< Scan type: Active = 0, Passive = 1
- u16 scantime; //!< Scan duration in milliseconds; if 0 default used
-};
-
-/**
- * @brief IOCTL input structure to configure an immediate scan cmd to firmware
- *
- * Used in the setuserscan (LBS_SET_USER_SCAN) private ioctl. Specifies
- * a number of parameters to be used in general for the scan as well
- * as a channel list (lbs_ioctl_user_scan_chan) for each scan period
- * desired.
- *
- * @sa lbs_set_user_scan_ioctl
- */
-struct lbs_ioctl_user_scan_cfg {
- /**
- * @brief BSS type to be sent in the firmware command
- *
- * Field can be used to restrict the types of networks returned in the
- * scan. valid settings are:
- *
- * - LBS_SCAN_BSS_TYPE_BSS (infrastructure)
- * - LBS_SCAN_BSS_TYPE_IBSS (adhoc)
- * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
- */
- u8 bsstype;
-
- /**
- * @brief BSSID filter sent in the firmware command to limit the results
- */
- u8 bssid[ETH_ALEN];
-
- /* Clear existing scan results matching this BSSID */
- u8 clear_bssid;
-
- /**
- * @brief SSID filter sent in the firmware command to limit the results
- */
- char ssid[IW_ESSID_MAX_SIZE];
- u8 ssid_len;
-
- /* Clear existing scan results matching this SSID */
- u8 clear_ssid;
-};
-
-/**
* @brief Structure used to store information for each beacon/probe response
*/
struct bss_descriptor {
u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode);
int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
- u8 ssid_len, u8 clear_ssid);
-
-int lbs_cmd_80211_scan(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- void *pdata_buf);
-
-int lbs_ret_80211_scan(struct lbs_private *priv,
- struct cmd_ds_command *resp);
-
-int lbs_scan_networks(struct lbs_private *priv,
- const struct lbs_ioctl_user_scan_cfg *puserscanin,
- int full_scan);
-
-struct ifreq;
+ u8 ssid_len);
-struct iw_point;
-struct iw_param;
-struct iw_request_info;
int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra);
int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra);
+ union iwreq_data *wrqu, char *extra);
void lbs_scan_worker(struct work_struct *work);
struct led_pin ledpin[1];
} __attribute__ ((packed));
+struct led_bhv {
+ uint8_t firmwarestate;
+ uint8_t led;
+ uint8_t ledstate;
+ uint8_t ledarg;
+} __attribute__ ((packed));
+
+
+struct mrvlietypes_ledbhv {
+ struct mrvlietypesheader header;
+ struct led_bhv ledbhv[1];
+} __attribute__ ((packed));
+
#endif
range->num_bitrates);
range->num_frequency = 0;
+
+ range->scan_capa = IW_SCAN_CAPA_ESSID;
+
if (priv->enable11d &&
(priv->connect_status == LBS_CONNECTED ||
priv->mesh_connect_status == LBS_CONNECTED)) {
unsigned int tx_hdr_len;
void *cached_vdcf;
unsigned int fw_var;
- /* FIXME: this channels/modes/rates stuff sucks */
- struct ieee80211_channel channels[14];
- struct ieee80211_rate rates[12];
- struct ieee80211_hw_mode modes[2];
struct ieee80211_tx_queue_stats tx_stats;
};
MODULE_LICENSE("GPL");
MODULE_ALIAS("prism54common");
+static struct ieee80211_rate p54_rates[] = {
+ { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct ieee80211_channel p54_channels[] = {
+ { .center_freq = 2412, .hw_value = 1, },
+ { .center_freq = 2417, .hw_value = 2, },
+ { .center_freq = 2422, .hw_value = 3, },
+ { .center_freq = 2427, .hw_value = 4, },
+ { .center_freq = 2432, .hw_value = 5, },
+ { .center_freq = 2437, .hw_value = 6, },
+ { .center_freq = 2442, .hw_value = 7, },
+ { .center_freq = 2447, .hw_value = 8, },
+ { .center_freq = 2452, .hw_value = 9, },
+ { .center_freq = 2457, .hw_value = 10, },
+ { .center_freq = 2462, .hw_value = 11, },
+ { .center_freq = 2467, .hw_value = 12, },
+ { .center_freq = 2472, .hw_value = 13, },
+ { .center_freq = 2484, .hw_value = 14, },
+};
+
+static struct ieee80211_supported_band band_2GHz = {
+ .channels = p54_channels,
+ .n_channels = ARRAY_SIZE(p54_channels),
+ .bitrates = p54_rates,
+ .n_bitrates = ARRAY_SIZE(p54_rates),
+};
+
+
void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
{
struct p54_common *priv = dev->priv;
/* make it overrun */
entry_len = len;
break;
+ default:
+ printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n",
+ le16_to_cpu(entry->code));
+ break;
}
entry = (void *)entry + (entry_len + 1)*2;
u16 freq = le16_to_cpu(hdr->freq);
rx_status.ssi = hdr->rssi;
- rx_status.rate = hdr->rate & 0x1f; /* report short preambles & CCK too */
- rx_status.channel = freq == 2484 ? 14 : (freq - 2407)/5;
+ /* XX correct? */
+ rx_status.rate_idx = hdr->rate & 0xf;
rx_status.freq = freq;
- rx_status.phymode = MODE_IEEE80211G;
+ rx_status.band = IEEE80211_BAND_2GHZ;
rx_status.antenna = hdr->antenna;
rx_status.mactime = le64_to_cpu(hdr->timestamp);
rx_status.flag |= RX_FLAG_TSFT;
while (entry != (struct sk_buff *)&priv->tx_queue) {
range = (struct memrecord *)&entry->cb;
if (range->start_addr == addr) {
- struct ieee80211_tx_status status = {{0}};
+ struct ieee80211_tx_status status;
struct p54_control_hdr *entry_hdr;
struct p54_tx_control_allocdata *entry_data;
int pad = 0;
kfree_skb(entry);
break;
}
+ memset(&status, 0, sizeof(status));
memcpy(&status.control, range->control,
sizeof(status.control));
kfree(range->control);
txhdr->padding2 = 0;
/* TODO: add support for alternate retry TX rates */
- rate = control->tx_rate;
+ rate = control->tx_rate->hw_value;
+ if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+ rate |= 0x10;
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
rate |= 0x40;
else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
return 0;
}
-#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, burst) \
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
do { \
queue.aifs = cpu_to_le16(ai_fs); \
queue.cwmin = cpu_to_le16(cw_min); \
queue.cwmax = cpu_to_le16(cw_max); \
- queue.txop = (burst == 0) ? \
- 0 : cpu_to_le16((burst * 100) / 32 + 1); \
+ queue.txop = cpu_to_le16(_txop); \
} while(0)
static void p54_init_vdcf(struct ieee80211_hw *dev)
vdcf = (struct p54_tx_control_vdcf *) hdr->data;
- P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 0x000f);
- P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 0x001e);
- P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 0x0014);
- P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0x0000);
+ P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 47);
+ P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 94);
+ P54_SET_QUEUE(vdcf->queue[2], 0x0003, 0x000f, 0x03ff, 0);
+ P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0);
}
static void p54_set_vdcf(struct ieee80211_hw *dev)
{
int ret;
- ret = p54_set_freq(dev, cpu_to_le16(conf->freq));
+ ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
p54_set_vdcf(dev);
return ret;
}
if ((params) && !((queue < 0) || (queue > 4))) {
P54_SET_QUEUE(vdcf->queue[queue], params->aifs,
- params->cw_min, params->cw_max, params->burst_time);
+ params->cw_min, params->cw_max, params->txop);
} else
return -EINVAL;
{
struct ieee80211_hw *dev;
struct p54_common *priv;
- int i;
dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
if (!dev)
priv = dev->priv;
priv->mode = IEEE80211_IF_TYPE_INVALID;
skb_queue_head_init(&priv->tx_queue);
- memcpy(priv->channels, p54_channels, sizeof(p54_channels));
- memcpy(priv->rates, p54_rates, sizeof(p54_rates));
- priv->modes[1].mode = MODE_IEEE80211B;
- priv->modes[1].num_rates = 4;
- priv->modes[1].rates = priv->rates;
- priv->modes[1].num_channels = ARRAY_SIZE(p54_channels);
- priv->modes[1].channels = priv->channels;
- priv->modes[0].mode = MODE_IEEE80211G;
- priv->modes[0].num_rates = ARRAY_SIZE(p54_rates);
- priv->modes[0].rates = priv->rates;
- priv->modes[0].num_channels = ARRAY_SIZE(p54_channels);
- priv->modes[0].channels = priv->channels;
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
IEEE80211_HW_RX_INCLUDES_FCS;
dev->channel_change_time = 1000; /* TODO: find actual value */
p54_init_vdcf(dev);
- for (i = 0; i < 2; i++) {
- if (ieee80211_register_hwmode(dev, &priv->modes[i])) {
- kfree(priv->cached_vdcf);
- ieee80211_free_hw(dev);
- return NULL;
- }
- }
-
return dev;
}
EXPORT_SYMBOL_GPL(p54_init_common);
__le16 frameburst;
} __attribute__ ((packed));
-static const struct ieee80211_rate p54_rates[] = {
- { .rate = 10,
- .val = 0,
- .val2 = 0x10,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 20,
- .val = 1,
- .val2 = 0x11,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 55,
- .val = 2,
- .val2 = 0x12,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 110,
- .val = 3,
- .val2 = 0x13,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 60,
- .val = 4,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 90,
- .val = 5,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 120,
- .val = 6,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 180,
- .val = 7,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 240,
- .val = 8,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 360,
- .val = 9,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 480,
- .val = 10,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 540,
- .val = 11,
- .flags = IEEE80211_RATE_OFDM },
-};
-
-// TODO: just generate this..
-static const struct ieee80211_channel p54_channels[] = {
- { .chan = 1,
- .freq = 2412},
- { .chan = 2,
- .freq = 2417},
- { .chan = 3,
- .freq = 2422},
- { .chan = 4,
- .freq = 2427},
- { .chan = 5,
- .freq = 2432},
- { .chan = 6,
- .freq = 2437},
- { .chan = 7,
- .freq = 2442},
- { .chan = 8,
- .freq = 2447},
- { .chan = 9,
- .freq = 2452},
- { .chan = 10,
- .freq = 2457},
- { .chan = 11,
- .freq = 2462},
- { .chan = 12,
- .freq = 2467},
- { .chan = 13,
- .freq = 2472},
- { .chan = 14,
- .freq = 2484}
-};
-
#endif /* PRISM54COMMON_H */
struct obj_bss bss, *bss2;
union oid_res_t r;
- down(&priv->stats_sem);
+ mutex_lock(&priv->stats_lock);
/* Noise floor.
* I'm not sure if the unit is dBm.
mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r);
priv->local_iwstatistics.discard.retries = r.u;
- up(&priv->stats_sem);
+ mutex_unlock(&priv->stats_lock);
return;
}
islpci_private *priv = netdev_priv(ndev);
/* If the stats are being updated return old data */
- if (down_trylock(&priv->stats_sem) == 0) {
+ if (mutex_trylock(&priv->stats_lock) == 0) {
memcpy(&priv->iwstatistics, &priv->local_iwstatistics,
sizeof (struct iw_statistics));
/* They won't be marked updated for the next time */
priv->local_iwstatistics.qual.updated = 0;
- up(&priv->stats_sem);
+ mutex_unlock(&priv->stats_lock);
} else
priv->iwstatistics.qual.updated = 0;
void
prism54_acl_init(struct islpci_acl *acl)
{
- sema_init(&acl->sem, 1);
+ mutex_init(&acl->lock);
INIT_LIST_HEAD(&acl->mac_list);
acl->size = 0;
acl->policy = MAC_POLICY_OPEN;
struct list_head *ptr, *next;
struct mac_entry *entry;
- down(&acl->sem);
+ mutex_lock(&acl->lock);
if (acl->size == 0) {
- up(&acl->sem);
+ mutex_unlock(&acl->lock);
return;
}
kfree(entry);
}
acl->size = 0;
- up(&acl->sem);
+ mutex_unlock(&acl->lock);
}
void
memcpy(entry->addr, addr->sa_data, ETH_ALEN);
- if (down_interruptible(&acl->sem)) {
+ if (mutex_lock_interruptible(&acl->lock)) {
kfree(entry);
return -ERESTARTSYS;
}
list_add_tail(&entry->_list, &acl->mac_list);
acl->size++;
- up(&acl->sem);
+ mutex_unlock(&acl->lock);
return 0;
}
if (addr->sa_family != ARPHRD_ETHER)
return -EOPNOTSUPP;
- if (down_interruptible(&acl->sem))
+ if (mutex_lock_interruptible(&acl->lock))
return -ERESTARTSYS;
list_for_each_entry(entry, &acl->mac_list, _list) {
if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) {
list_del(&entry->_list);
acl->size--;
kfree(entry);
- up(&acl->sem);
+ mutex_unlock(&acl->lock);
return 0;
}
}
- up(&acl->sem);
+ mutex_unlock(&acl->lock);
return -EINVAL;
}
dwrq->length = 0;
- if (down_interruptible(&acl->sem))
+ if (mutex_lock_interruptible(&acl->lock))
return -ERESTARTSYS;
list_for_each_entry(entry, &acl->mac_list, _list) {
dwrq->length++;
dst++;
}
- up(&acl->sem);
+ mutex_unlock(&acl->lock);
return 0;
}
struct mac_entry *entry;
int res = 0;
- if (down_interruptible(&acl->sem))
+ if (mutex_lock_interruptible(&acl->lock))
return -ERESTARTSYS;
if (acl->policy == MAC_POLICY_OPEN) {
- up(&acl->sem);
+ mutex_unlock(&acl->lock);
return 1;
}
}
}
res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res;
- up(&acl->sem);
+ mutex_unlock(&acl->lock);
return res;
}
if (wpa_ie_len > MAX_WPA_IE_LEN)
wpa_ie_len = MAX_WPA_IE_LEN;
- down(&priv->wpa_sem);
+ mutex_lock(&priv->wpa_lock);
/* try to use existing entry */
list_for_each(ptr, &priv->bss_wpa_list) {
kfree(bss);
}
- up(&priv->wpa_sem);
+ mutex_unlock(&priv->wpa_lock);
}
static size_t
struct islpci_bss_wpa_ie *bss = NULL;
size_t len = 0;
- down(&priv->wpa_sem);
+ mutex_lock(&priv->wpa_lock);
list_for_each(ptr, &priv->bss_wpa_list) {
bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
len = bss->wpa_ie_len;
memcpy(wpa_ie, bss->wpa_ie, len);
}
- up(&priv->wpa_sem);
+ mutex_unlock(&priv->wpa_lock);
return len;
}
prism54_wpa_bss_ie_init(islpci_private *priv)
{
INIT_LIST_HEAD(&priv->bss_wpa_list);
- sema_init(&priv->wpa_sem, 1);
+ mutex_init(&priv->wpa_lock);
}
void
mutex_init(&priv->mgmt_lock);
priv->mgmt_received = NULL;
init_waitqueue_head(&priv->mgmt_wqueue);
- sema_init(&priv->stats_sem, 1);
+ mutex_init(&priv->stats_lock);
spin_lock_init(&priv->slock);
/* init state machine with off#1 state */
enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy;
struct list_head mac_list; /* a list of mac_entry */
int size; /* size of queue */
- struct semaphore sem; /* accessed in ioctls and trap_work */
+ struct mutex lock; /* accessed in ioctls and trap_work */
};
struct islpci_membuf {
/* Take care of the wireless stats */
struct work_struct stats_work;
- struct semaphore stats_sem;
+ struct mutex stats_lock;
/* remember when we last updated the stats */
unsigned long stats_timestamp;
/* The first is accessed under semaphore locking.
int wpa; /* WPA mode enabled */
struct list_head bss_wpa_list;
int num_bss_wpa;
- struct semaphore wpa_sem;
+ struct mutex wpa_lock;
u8 wpa_ie[MAX_WPA_IE_LEN];
size_t wpa_ie_len;
#define NDIS_802_11_LENGTH_RATES 8
#define NDIS_802_11_LENGTH_RATES_EX 16
-struct NDIS_802_11_SSID {
- __le32 SsidLength;
- u8 Ssid[NDIS_802_11_LENGTH_SSID];
-} __attribute__((packed));
-
-enum NDIS_802_11_NETWORK_TYPE {
- Ndis802_11FH,
- Ndis802_11DS,
- Ndis802_11OFDM5,
- Ndis802_11OFDM24,
- Ndis802_11NetworkTypeMax
+enum ndis_80211_net_type {
+ ndis_80211_type_freq_hop,
+ ndis_80211_type_direct_seq,
+ ndis_80211_type_ofdm_a,
+ ndis_80211_type_ofdm_g
};
-struct NDIS_802_11_CONFIGURATION_FH {
- __le32 Length;
- __le32 HopPattern;
- __le32 HopSet;
- __le32 DwellTime;
-} __attribute__((packed));
-
-struct NDIS_802_11_CONFIGURATION {
- __le32 Length;
- __le32 BeaconPeriod;
- __le32 ATIMWindow;
- __le32 DSConfig;
- struct NDIS_802_11_CONFIGURATION_FH FHConfig;
-} __attribute__((packed));
-
-enum NDIS_802_11_NETWORK_INFRASTRUCTURE {
- Ndis802_11IBSS,
- Ndis802_11Infrastructure,
- Ndis802_11AutoUnknown,
- Ndis802_11InfrastructureMax
+enum ndis_80211_net_infra {
+ ndis_80211_infra_adhoc,
+ ndis_80211_infra_infra,
+ ndis_80211_infra_auto_unknown
};
-enum NDIS_802_11_AUTHENTICATION_MODE {
- Ndis802_11AuthModeOpen,
- Ndis802_11AuthModeShared,
- Ndis802_11AuthModeAutoSwitch,
- Ndis802_11AuthModeWPA,
- Ndis802_11AuthModeWPAPSK,
- Ndis802_11AuthModeWPANone,
- Ndis802_11AuthModeWPA2,
- Ndis802_11AuthModeWPA2PSK,
- Ndis802_11AuthModeMax
+enum ndis_80211_auth_mode {
+ ndis_80211_auth_open,
+ ndis_80211_auth_shared,
+ ndis_80211_auth_auto_switch,
+ ndis_80211_auth_wpa,
+ ndis_80211_auth_wpa_psk,
+ ndis_80211_auth_wpa_none,
+ ndis_80211_auth_wpa2,
+ ndis_80211_auth_wpa2_psk
};
-enum NDIS_802_11_ENCRYPTION_STATUS {
- Ndis802_11WEPEnabled,
- Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
- Ndis802_11WEPDisabled,
- Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
- Ndis802_11WEPKeyAbsent,
- Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
- Ndis802_11WEPNotSupported,
- Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
- Ndis802_11Encryption2Enabled,
- Ndis802_11Encryption2KeyAbsent,
- Ndis802_11Encryption3Enabled,
- Ndis802_11Encryption3KeyAbsent
+enum ndis_80211_encr_status {
+ ndis_80211_encr_wep_enabled,
+ ndis_80211_encr_disabled,
+ ndis_80211_encr_wep_key_absent,
+ ndis_80211_encr_not_supported,
+ ndis_80211_encr_tkip_enabled,
+ ndis_80211_encr_tkip_key_absent,
+ ndis_80211_encr_ccmp_enabled,
+ ndis_80211_encr_ccmp_key_absent
};
-enum NDIS_802_11_PRIVACY_FILTER {
- Ndis802_11PrivFilterAcceptAll,
- Ndis802_11PrivFilter8021xWEP
+enum ndis_80211_priv_filter {
+ ndis_80211_priv_accept_all,
+ ndis_80211_priv_8021x_wep
};
-struct NDIS_WLAN_BSSID_EX {
- __le32 Length;
- u8 MacAddress[6];
- u8 Padding[2];
- struct NDIS_802_11_SSID Ssid;
- __le32 Privacy;
- __le32 Rssi;
- __le32 NetworkTypeInUse;
- struct NDIS_802_11_CONFIGURATION Configuration;
- __le32 InfrastructureMode;
- u8 SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
- __le32 IELength;
- u8 IEs[0];
+struct ndis_80211_ssid {
+ __le32 length;
+ u8 essid[NDIS_802_11_LENGTH_SSID];
+} __attribute__((packed));
+
+struct ndis_80211_conf_freq_hop {
+ __le32 length;
+ __le32 hop_pattern;
+ __le32 hop_set;
+ __le32 dwell_time;
+} __attribute__((packed));
+
+struct ndis_80211_conf {
+ __le32 length;
+ __le32 beacon_period;
+ __le32 atim_window;
+ __le32 ds_config;
+ struct ndis_80211_conf_freq_hop fh_config;
+} __attribute__((packed));
+
+struct ndis_80211_bssid_ex {
+ __le32 length;
+ u8 mac[6];
+ u8 padding[2];
+ struct ndis_80211_ssid ssid;
+ __le32 privacy;
+ __le32 rssi;
+ __le32 net_type;
+ struct ndis_80211_conf config;
+ __le32 net_infra;
+ u8 rates[NDIS_802_11_LENGTH_RATES_EX];
+ __le32 ie_length;
+ u8 ies[0];
} __attribute__((packed));
-struct NDIS_802_11_BSSID_LIST_EX {
- __le32 NumberOfItems;
- struct NDIS_WLAN_BSSID_EX Bssid[0];
+struct ndis_80211_bssid_list_ex {
+ __le32 num_items;
+ struct ndis_80211_bssid_ex bssid[0];
} __attribute__((packed));
-struct NDIS_802_11_FIXED_IEs {
- u8 Timestamp[8];
- __le16 BeaconInterval;
- __le16 Capabilities;
+struct ndis_80211_fixed_ies {
+ u8 timestamp[8];
+ __le16 beacon_interval;
+ __le16 capabilities;
} __attribute__((packed));
-struct NDIS_802_11_WEP {
- __le32 Length;
- __le32 KeyIndex;
- __le32 KeyLength;
- u8 KeyMaterial[32];
+struct ndis_80211_wep_key {
+ __le32 size;
+ __le32 index;
+ __le32 length;
+ u8 material[32];
} __attribute__((packed));
-struct NDIS_802_11_KEY {
- __le32 Length;
- __le32 KeyIndex;
- __le32 KeyLength;
- u8 Bssid[6];
- u8 Padding[6];
- u8 KeyRSC[8];
- u8 KeyMaterial[32];
+struct ndis_80211_key {
+ __le32 size;
+ __le32 index;
+ __le32 length;
+ u8 bssid[6];
+ u8 padding[6];
+ u8 rsc[8];
+ u8 material[32];
} __attribute__((packed));
-struct NDIS_802_11_REMOVE_KEY {
- __le32 Length;
- __le32 KeyIndex;
- u8 Bssid[6];
+struct ndis_80211_remove_key {
+ __le32 size;
+ __le32 index;
+ u8 bssid[6];
} __attribute__((packed));
-struct RNDIS_CONFIG_PARAMETER_INFOBUFFER {
- __le32 ParameterNameOffset;
- __le32 ParameterNameLength;
- __le32 ParameterType;
- __le32 ParameterValueOffset;
- __le32 ParameterValueLength;
+struct ndis_config_param {
+ __le32 name_offs;
+ __le32 name_length;
+ __le32 type;
+ __le32 value_offs;
+ __le32 value_length;
} __attribute__((packed));
/* these have to match what is in wpa_supplicant */
/* hardware state */
int radio_on;
int infra_mode;
- struct NDIS_802_11_SSID essid;
+ struct ndis_80211_ssid essid;
/* encryption stuff */
int encr_tx_key_index;
static int rndis_set_config_parameter(struct usbnet *dev, char *param,
int value_type, void *value)
{
- struct RNDIS_CONFIG_PARAMETER_INFOBUFFER *infobuf;
+ struct ndis_config_param *infobuf;
int value_len, info_len, param_len, ret, i;
__le16 *unibuf;
__le32 *dst_value;
devdbg(dev, "setting config parameter: %s, value: %d",
param, *(u32 *)value);
- infobuf->ParameterNameOffset = cpu_to_le32(sizeof(*infobuf));
- infobuf->ParameterNameLength = cpu_to_le32(param_len);
- infobuf->ParameterType = cpu_to_le32(value_type);
- infobuf->ParameterValueOffset = cpu_to_le32(sizeof(*infobuf) +
- param_len);
- infobuf->ParameterValueLength = cpu_to_le32(value_len);
+ infobuf->name_offs = cpu_to_le32(sizeof(*infobuf));
+ infobuf->name_length = cpu_to_le32(param_len);
+ infobuf->type = cpu_to_le32(value_type);
+ infobuf->value_offs = cpu_to_le32(sizeof(*infobuf) + param_len);
+ infobuf->value_length = cpu_to_le32(value_len);
/* simple string to unicode string conversion */
unibuf = (void *)infobuf + sizeof(*infobuf);
static int
add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index);
-static int get_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid)
+static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
{
int ret, len;
ret = rndis_query_oid(usbdev, OID_802_11_SSID, ssid, &len);
if (ret != 0)
- ssid->SsidLength = 0;
+ ssid->length = 0;
#ifdef DEBUG
{
unsigned char tmp[NDIS_802_11_LENGTH_SSID + 1];
- memcpy(tmp, ssid->Ssid, le32_to_cpu(ssid->SsidLength));
- tmp[le32_to_cpu(ssid->SsidLength)] = 0;
+ memcpy(tmp, ssid->essid, le32_to_cpu(ssid->length));
+ tmp[le32_to_cpu(ssid->length)] = 0;
devdbg(usbdev, "get_essid: '%s', ret: %d", tmp, ret);
}
#endif
}
-static int set_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid)
+static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
{
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
int ret;
static int disassociate(struct usbnet *usbdev, int reset_ssid)
{
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
- struct NDIS_802_11_SSID ssid;
+ struct ndis_80211_ssid ssid;
int i, ret = 0;
if (priv->radio_on) {
/* disassociate causes radio to be turned off; if reset_ssid
* is given, set random ssid to enable radio */
if (reset_ssid) {
- ssid.SsidLength = cpu_to_le32(sizeof(ssid.Ssid));
- get_random_bytes(&ssid.Ssid[2], sizeof(ssid.Ssid)-2);
- ssid.Ssid[0] = 0x1;
- ssid.Ssid[1] = 0xff;
- for (i = 2; i < sizeof(ssid.Ssid); i++)
- ssid.Ssid[i] = 0x1 + (ssid.Ssid[i] * 0xfe / 0xff);
+ ssid.length = cpu_to_le32(sizeof(ssid.essid));
+ get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2);
+ ssid.essid[0] = 0x1;
+ ssid.essid[1] = 0xff;
+ for (i = 2; i < sizeof(ssid.essid); i++)
+ ssid.essid[i] = 0x1 + (ssid.essid[i] * 0xfe / 0xff);
ret = set_essid(usbdev, &ssid);
}
return ret;
if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) {
if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
- auth_mode = Ndis802_11AuthModeWPA2;
+ auth_mode = ndis_80211_auth_wpa2;
else
- auth_mode = Ndis802_11AuthModeWPA2PSK;
+ auth_mode = ndis_80211_auth_wpa2_psk;
} else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) {
if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
- auth_mode = Ndis802_11AuthModeWPA;
+ auth_mode = ndis_80211_auth_wpa;
else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK)
- auth_mode = Ndis802_11AuthModeWPAPSK;
+ auth_mode = ndis_80211_auth_wpa_psk;
else
- auth_mode = Ndis802_11AuthModeWPANone;
+ auth_mode = ndis_80211_auth_wpa_none;
} else if (authalg & IW_AUTH_ALG_SHARED_KEY) {
if (authalg & IW_AUTH_ALG_OPEN_SYSTEM)
- auth_mode = Ndis802_11AuthModeAutoSwitch;
+ auth_mode = ndis_80211_auth_auto_switch;
else
- auth_mode = Ndis802_11AuthModeShared;
+ auth_mode = ndis_80211_auth_shared;
} else
- auth_mode = Ndis802_11AuthModeOpen;
+ auth_mode = ndis_80211_auth_open;
tmp = cpu_to_le32(auth_mode);
ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp,
if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 ||
priv->wpa_version & IW_AUTH_WPA_VERSION_WPA)
- tmp = cpu_to_le32(Ndis802_11PrivFilter8021xWEP);
+ tmp = cpu_to_le32(ndis_80211_priv_8021x_wep);
else
- tmp = cpu_to_le32(Ndis802_11PrivFilterAcceptAll);
+ tmp = cpu_to_le32(ndis_80211_priv_accept_all);
return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp,
sizeof(tmp));
groupwise);
if (pairwise & IW_AUTH_CIPHER_CCMP)
- encr_mode = Ndis802_11Encryption3Enabled;
+ encr_mode = ndis_80211_encr_ccmp_enabled;
else if (pairwise & IW_AUTH_CIPHER_TKIP)
- encr_mode = Ndis802_11Encryption2Enabled;
+ encr_mode = ndis_80211_encr_tkip_enabled;
else if (pairwise &
(IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
- encr_mode = Ndis802_11Encryption1Enabled;
+ encr_mode = ndis_80211_encr_wep_enabled;
else if (groupwise & IW_AUTH_CIPHER_CCMP)
- encr_mode = Ndis802_11Encryption3Enabled;
+ encr_mode = ndis_80211_encr_ccmp_enabled;
else if (groupwise & IW_AUTH_CIPHER_TKIP)
- encr_mode = Ndis802_11Encryption2Enabled;
+ encr_mode = ndis_80211_encr_tkip_enabled;
else
- encr_mode = Ndis802_11EncryptionDisabled;
+ encr_mode = ndis_80211_encr_disabled;
tmp = cpu_to_le32(encr_mode);
ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp,
priv->wpa_keymgmt = 0;
priv->wpa_version = 0;
- set_infra_mode(usbdev, Ndis802_11Infrastructure);
+ set_infra_mode(usbdev, ndis_80211_infra_infra);
set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
IW_AUTH_ALG_OPEN_SYSTEM);
set_priv_filter(usbdev);
static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
{
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
- struct NDIS_802_11_WEP ndis_key;
+ struct ndis_80211_wep_key ndis_key;
int ret;
if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4)
memset(&ndis_key, 0, sizeof(ndis_key));
- ndis_key.Length = cpu_to_le32(sizeof(ndis_key));
- ndis_key.KeyLength = cpu_to_le32(key_len);
- ndis_key.KeyIndex = cpu_to_le32(index);
- memcpy(&ndis_key.KeyMaterial, key, key_len);
+ ndis_key.size = cpu_to_le32(sizeof(ndis_key));
+ ndis_key.length = cpu_to_le32(key_len);
+ ndis_key.index = cpu_to_le32(index);
+ memcpy(&ndis_key.material, key, key_len);
if (index == priv->encr_tx_key_index) {
- ndis_key.KeyIndex |= cpu_to_le32(1 << 31);
+ ndis_key.index |= cpu_to_le32(1 << 31);
ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104,
IW_AUTH_CIPHER_NONE);
if (ret)
static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
{
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
- struct NDIS_802_11_REMOVE_KEY remove_key;
+ struct ndis_80211_remove_key remove_key;
__le32 keyindex;
int ret;
priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP ||
priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP ||
priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) {
- remove_key.Length = cpu_to_le32(sizeof(remove_key));
- remove_key.KeyIndex = cpu_to_le32(index);
+ remove_key.size = cpu_to_le32(sizeof(remove_key));
+ remove_key.index = cpu_to_le32(index);
if (bssid) {
/* pairwise key */
if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0)
- remove_key.KeyIndex |= cpu_to_le32(1 << 30);
- memcpy(remove_key.Bssid, bssid,
- sizeof(remove_key.Bssid));
+ remove_key.index |= cpu_to_le32(1 << 30);
+ memcpy(remove_key.bssid, bssid,
+ sizeof(remove_key.bssid));
} else
- memset(remove_key.Bssid, 0xff,
- sizeof(remove_key.Bssid));
+ memset(remove_key.bssid, 0xff,
+ sizeof(remove_key.bssid));
ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_KEY, &remove_key,
sizeof(remove_key));
static int rndis_iw_set_essid(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
{
- struct NDIS_802_11_SSID ssid;
+ struct ndis_80211_ssid ssid;
int length = wrqu->essid.length;
struct usbnet *usbdev = dev->priv;
if (length > NDIS_802_11_LENGTH_SSID)
length = NDIS_802_11_LENGTH_SSID;
- ssid.SsidLength = cpu_to_le32(length);
+ ssid.length = cpu_to_le32(length);
if (length > 0)
- memcpy(ssid.Ssid, essid, length);
+ memcpy(ssid.essid, essid, length);
else
- memset(ssid.Ssid, 0, NDIS_802_11_LENGTH_SSID);
+ memset(ssid.essid, 0, NDIS_802_11_LENGTH_SSID);
set_assoc_params(usbdev);
static int rndis_iw_get_essid(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
{
- struct NDIS_802_11_SSID ssid;
+ struct ndis_80211_ssid ssid;
struct usbnet *usbdev = dev->priv;
int ret;
ret = get_essid(usbdev, &ssid);
- if (ret == 0 && le32_to_cpu(ssid.SsidLength) > 0) {
+ if (ret == 0 && le32_to_cpu(ssid.length) > 0) {
wrqu->essid.flags = 1;
- wrqu->essid.length = le32_to_cpu(ssid.SsidLength);
- memcpy(essid, ssid.Ssid, wrqu->essid.length);
+ wrqu->essid.length = le32_to_cpu(ssid.length);
+ memcpy(essid, ssid.essid, wrqu->essid.length);
essid[wrqu->essid.length] = 0;
} else {
memset(essid, 0, sizeof(NDIS_802_11_LENGTH_SSID));
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
switch (priv->infra_mode) {
- case Ndis802_11IBSS:
+ case ndis_80211_infra_adhoc:
wrqu->mode = IW_MODE_ADHOC;
break;
- case Ndis802_11Infrastructure:
+ case ndis_80211_infra_infra:
wrqu->mode = IW_MODE_INFRA;
break;
- /*case Ndis802_11AutoUnknown:*/
+ /*case ndis_80211_infra_auto_unknown:*/
default:
wrqu->mode = IW_MODE_AUTO;
break;
switch (wrqu->mode) {
case IW_MODE_ADHOC:
- mode = Ndis802_11IBSS;
+ mode = ndis_80211_infra_adhoc;
break;
case IW_MODE_INFRA:
- mode = Ndis802_11Infrastructure;
+ mode = ndis_80211_infra_infra;
break;
/*case IW_MODE_AUTO:*/
default:
- mode = Ndis802_11AutoUnknown;
+ mode = ndis_80211_infra_auto_unknown;
break;
}
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
struct usbnet *usbdev = dev->priv;
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
- struct NDIS_802_11_KEY ndis_key;
+ struct ndis_80211_key ndis_key;
int keyidx, ret;
u8 *addr;
ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0)
return remove_key(usbdev, keyidx, NULL);
- if (ext->key_len > sizeof(ndis_key.KeyMaterial))
+ if (ext->key_len > sizeof(ndis_key.material))
return -1;
memset(&ndis_key, 0, sizeof(ndis_key));
- ndis_key.Length = cpu_to_le32(sizeof(ndis_key) -
- sizeof(ndis_key.KeyMaterial) + ext->key_len);
- ndis_key.KeyLength = cpu_to_le32(ext->key_len);
- ndis_key.KeyIndex = cpu_to_le32(keyidx);
+ ndis_key.size = cpu_to_le32(sizeof(ndis_key) -
+ sizeof(ndis_key.material) + ext->key_len);
+ ndis_key.length = cpu_to_le32(ext->key_len);
+ ndis_key.index = cpu_to_le32(keyidx);
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
- memcpy(ndis_key.KeyRSC, ext->rx_seq, 6);
- ndis_key.KeyIndex |= cpu_to_le32(1 << 29);
+ memcpy(ndis_key.rsc, ext->rx_seq, 6);
+ ndis_key.index |= cpu_to_le32(1 << 29);
}
addr = ext->addr.sa_data;
if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
/* group key */
- if (priv->infra_mode == Ndis802_11IBSS)
- memset(ndis_key.Bssid, 0xff, ETH_ALEN);
+ if (priv->infra_mode == ndis_80211_infra_adhoc)
+ memset(ndis_key.bssid, 0xff, ETH_ALEN);
else
- get_bssid(usbdev, ndis_key.Bssid);
+ get_bssid(usbdev, ndis_key.bssid);
} else {
/* pairwise key */
- ndis_key.KeyIndex |= cpu_to_le32(1 << 30);
- memcpy(ndis_key.Bssid, addr, ETH_ALEN);
+ ndis_key.index |= cpu_to_le32(1 << 30);
+ memcpy(ndis_key.bssid, addr, ETH_ALEN);
}
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
- ndis_key.KeyIndex |= cpu_to_le32(1 << 31);
+ ndis_key.index |= cpu_to_le32(1 << 31);
if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) {
/* wpa_supplicant gives us the Michael MIC RX/TX keys in
* different order than NDIS spec, so swap the order here. */
- memcpy(ndis_key.KeyMaterial, ext->key, 16);
- memcpy(ndis_key.KeyMaterial + 16, ext->key + 24, 8);
- memcpy(ndis_key.KeyMaterial + 24, ext->key + 16, 8);
+ memcpy(ndis_key.material, ext->key, 16);
+ memcpy(ndis_key.material + 16, ext->key + 24, 8);
+ memcpy(ndis_key.material + 24, ext->key + 16, 8);
} else
- memcpy(ndis_key.KeyMaterial, ext->key, ext->key_len);
+ memcpy(ndis_key.material, ext->key, ext->key_len);
ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key,
- le32_to_cpu(ndis_key.Length));
+ le32_to_cpu(ndis_key.size));
devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret);
if (ret != 0)
return ret;
priv->encr_key_len[keyidx] = ext->key_len;
- memcpy(&priv->encr_keys[keyidx], ndis_key.KeyMaterial, ext->key_len);
+ memcpy(&priv->encr_keys[keyidx], ndis_key.material, ext->key_len);
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
priv->encr_tx_key_index = keyidx;
static char *rndis_translate_scan(struct net_device *dev,
- char *cev, char *end_buf, struct NDIS_WLAN_BSSID_EX *bssid)
+ char *cev, char *end_buf, struct ndis_80211_bssid_ex *bssid)
{
#ifdef DEBUG
struct usbnet *usbdev = dev->priv;
unsigned char sbuf[32];
DECLARE_MAC_BUF(mac);
- bssid_len = le32_to_cpu(bssid->Length);
+ bssid_len = le32_to_cpu(bssid->length);
- devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->MacAddress));
+ devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->mac));
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bssid->MacAddress, ETH_ALEN);
+ memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN);
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
- devdbg(usbdev, "SSID(%d) %s",
- le32_to_cpu(bssid->Ssid.SsidLength),
- bssid->Ssid.Ssid);
+ devdbg(usbdev, "SSID(%d) %s", le32_to_cpu(bssid->ssid.length),
+ bssid->ssid.essid);
iwe.cmd = SIOCGIWESSID;
- iwe.u.essid.length = le32_to_cpu(bssid->Ssid.SsidLength);
+ iwe.u.essid.length = le32_to_cpu(bssid->ssid.length);
iwe.u.essid.flags = 1;
- cev = iwe_stream_add_point(cev, end_buf, &iwe,
- bssid->Ssid.Ssid);
+ cev = iwe_stream_add_point(cev, end_buf, &iwe, bssid->ssid.essid);
- devdbg(usbdev, "MODE %d",
- le32_to_cpu(bssid->InfrastructureMode));
+ devdbg(usbdev, "MODE %d", le32_to_cpu(bssid->net_infra));
iwe.cmd = SIOCGIWMODE;
- switch (le32_to_cpu(bssid->InfrastructureMode)) {
- case Ndis802_11IBSS:
+ switch (le32_to_cpu(bssid->net_infra)) {
+ case ndis_80211_infra_adhoc:
iwe.u.mode = IW_MODE_ADHOC;
break;
- case Ndis802_11Infrastructure:
+ case ndis_80211_infra_infra:
iwe.u.mode = IW_MODE_INFRA;
break;
- /*case Ndis802_11AutoUnknown:*/
+ /*case ndis_80211_infra_auto_unknown:*/
default:
iwe.u.mode = IW_MODE_AUTO;
break;
}
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
- devdbg(usbdev, "FREQ %d kHz",
- le32_to_cpu(bssid->Configuration.DSConfig));
+ devdbg(usbdev, "FREQ %d kHz", le32_to_cpu(bssid->config.ds_config));
iwe.cmd = SIOCGIWFREQ;
- dsconfig_to_freq(le32_to_cpu(bssid->Configuration.DSConfig),
- &iwe.u.freq);
+ dsconfig_to_freq(le32_to_cpu(bssid->config.ds_config), &iwe.u.freq);
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
- devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->Rssi));
+ devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi));
iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = level_to_qual(le32_to_cpu(bssid->Rssi));
- iwe.u.qual.level = le32_to_cpu(bssid->Rssi);
+ iwe.u.qual.qual = level_to_qual(le32_to_cpu(bssid->rssi));
+ iwe.u.qual.level = le32_to_cpu(bssid->rssi);
iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
| IW_QUAL_NOISE_INVALID;
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
- devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->Privacy));
+ devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->privacy));
iwe.cmd = SIOCGIWENCODE;
iwe.u.data.length = 0;
- if (le32_to_cpu(bssid->Privacy) == Ndis802_11PrivFilterAcceptAll)
+ if (le32_to_cpu(bssid->privacy) == ndis_80211_priv_accept_all)
iwe.u.data.flags = IW_ENCODE_DISABLED;
else
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
devdbg(usbdev, "RATES:");
current_val = cev + IW_EV_LCP_LEN;
iwe.cmd = SIOCGIWRATE;
- for (i = 0; i < sizeof(bssid->SupportedRates); i++) {
- if (bssid->SupportedRates[i] & 0x7f) {
+ for (i = 0; i < sizeof(bssid->rates); i++) {
+ if (bssid->rates[i] & 0x7f) {
iwe.u.bitrate.value =
- ((bssid->SupportedRates[i] & 0x7f) *
+ ((bssid->rates[i] & 0x7f) *
500000);
devdbg(usbdev, " %d", iwe.u.bitrate.value);
current_val = iwe_stream_add_value(cev,
if ((current_val - cev) > IW_EV_LCP_LEN)
cev = current_val;
- beacon = le32_to_cpu(bssid->Configuration.BeaconPeriod);
+ beacon = le32_to_cpu(bssid->config.beacon_period);
devdbg(usbdev, "BCN_INT %d", beacon);
iwe.cmd = IWEVCUSTOM;
snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon);
iwe.u.data.length = strlen(sbuf);
cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
- atim = le32_to_cpu(bssid->Configuration.ATIMWindow);
+ atim = le32_to_cpu(bssid->config.atim_window);
devdbg(usbdev, "ATIM %d", atim);
iwe.cmd = IWEVCUSTOM;
snprintf(sbuf, sizeof(sbuf), "atim=%u", atim);
iwe.u.data.length = strlen(sbuf);
cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
- ie = (void *)(bssid->IEs + sizeof(struct NDIS_802_11_FIXED_IEs));
+ ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies));
ie_len = min(bssid_len - (int)sizeof(*bssid),
- (int)le32_to_cpu(bssid->IELength));
- ie_len -= sizeof(struct NDIS_802_11_FIXED_IEs);
+ (int)le32_to_cpu(bssid->ie_length));
+ ie_len -= sizeof(struct ndis_80211_fixed_ies);
while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) {
if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 &&
memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) ||
struct usbnet *usbdev = dev->priv;
void *buf = NULL;
char *cev = extra;
- struct NDIS_802_11_BSSID_LIST_EX *bssid_list;
- struct NDIS_WLAN_BSSID_EX *bssid;
+ struct ndis_80211_bssid_list_ex *bssid_list;
+ struct ndis_80211_bssid_ex *bssid;
int ret = -EINVAL, len, count, bssid_len;
devdbg(usbdev, "SIOCGIWSCAN");
goto out;
bssid_list = buf;
- bssid = bssid_list->Bssid;
- bssid_len = le32_to_cpu(bssid->Length);
- count = le32_to_cpu(bssid_list->NumberOfItems);
+ bssid = bssid_list->bssid;
+ bssid_len = le32_to_cpu(bssid->length);
+ count = le32_to_cpu(bssid_list->num_items);
devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count);
while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
cev = rndis_translate_scan(dev, cev, extra + IW_SCAN_MAX_DATA,
bssid);
bssid = (void *)bssid + bssid_len;
- bssid_len = le32_to_cpu(bssid->Length);
+ bssid_len = le32_to_cpu(bssid->length);
count--;
}
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
struct usbnet *usbdev = dev->priv;
- struct NDIS_802_11_CONFIGURATION config;
+ struct ndis_80211_conf config;
unsigned int dsconfig;
int len, ret;
return 0;
}
- config.DSConfig = cpu_to_le32(dsconfig);
+ config.ds_config = cpu_to_le32(dsconfig);
devdbg(usbdev, "SIOCSIWFREQ: %d * 10^%d", wrqu->freq.m, wrqu->freq.e);
return rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
struct usbnet *usbdev = dev->priv;
- struct NDIS_802_11_CONFIGURATION config;
+ struct ndis_80211_conf config;
int len, ret;
len = sizeof(config);
ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
if (ret == 0)
- dsconfig_to_freq(le32_to_cpu(config.DSConfig), &wrqu->freq);
+ dsconfig_to_freq(le32_to_cpu(config.ds_config), &wrqu->freq);
devdbg(usbdev, "SIOCGIWFREQ: %d", wrqu->freq.m);
return ret;
n = 8;
for (i = 0; i < n; i++) {
switch (le32_to_cpu(networks_supported.items[i])) {
- case Ndis802_11FH:
- case Ndis802_11DS:
+ case ndis_80211_type_freq_hop:
+ case ndis_80211_type_direct_seq:
priv->caps |= CAP_MODE_80211B;
break;
- case Ndis802_11OFDM5:
+ case ndis_80211_type_ofdm_a:
priv->caps |= CAP_MODE_80211A;
break;
- case Ndis802_11OFDM24:
+ case ndis_80211_type_ofdm_g:
priv->caps |= CAP_MODE_80211G;
break;
}
This will enable the experimental support for the Ralink drivers,
developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
- These drivers will make use of the Devicescape ieee80211 stack.
+ These drivers will make use of the mac80211 stack.
When building one of the individual drivers, the rt2x00 library
will also be created. That library (when the driver is built as
a module) will be called "rt2x00lib.ko".
+if RT2X00
+
config RT2X00_LIB
tristate
- depends on RT2X00
config RT2X00_LIB_PCI
tristate
- depends on RT2X00
select RT2X00_LIB
config RT2X00_LIB_USB
tristate
- depends on RT2X00
select RT2X00_LIB
config RT2X00_LIB_FIRMWARE
boolean
depends on RT2X00_LIB
- select CRC_ITU_T
select FW_LOADER
config RT2X00_LIB_RFKILL
select RFKILL
select INPUT_POLLDEV
+config RT2X00_LIB_LEDS
+ boolean
+ depends on RT2X00_LIB
+ select NEW_LEDS
+ select LEDS_CLASS
+ select LEDS_TRIGGERS
+ select MAC80211_LEDS
+
config RT2400PCI
tristate "Ralink rt2400 pci/pcmcia support"
- depends on RT2X00 && PCI
+ depends on PCI
select RT2X00_LIB_PCI
select EEPROM_93CX6
---help---
hardware button to control the radio state.
This feature depends on the RF switch subsystem rfkill.
+config RT2400PCI_LEDS
+ bool "RT2400 leds support"
+ depends on RT2400PCI
+ select RT2X00_LIB_LEDS
+ ---help---
+ This adds support for led triggers provided my mac80211.
+
config RT2500PCI
tristate "Ralink rt2500 pci/pcmcia support"
- depends on RT2X00 && PCI
+ depends on PCI
select RT2X00_LIB_PCI
select EEPROM_93CX6
---help---
hardware button to control the radio state.
This feature depends on the RF switch subsystem rfkill.
+config RT2500PCI_LEDS
+ bool "RT2500 leds support"
+ depends on RT2500PCI
+ select RT2X00_LIB_LEDS
+ ---help---
+ This adds support for led triggers provided my mac80211.
+
config RT61PCI
tristate "Ralink rt61 pci/pcmcia support"
- depends on RT2X00 && PCI
+ depends on PCI
select RT2X00_LIB_PCI
select RT2X00_LIB_FIRMWARE
+ select CRC_ITU_T
select EEPROM_93CX6
---help---
This is an experimental driver for the Ralink rt61 wireless chip.
hardware button to control the radio state.
This feature depends on the RF switch subsystem rfkill.
+config RT61PCI_LEDS
+ bool "RT61 leds support"
+ depends on RT61PCI
+ select RT2X00_LIB_LEDS
+ ---help---
+ This adds support for led triggers provided my mac80211.
+
config RT2500USB
tristate "Ralink rt2500 usb support"
- depends on RT2X00 && USB
+ depends on USB
select RT2X00_LIB_USB
---help---
This is an experimental driver for the Ralink rt2500 wireless chip.
When compiled as a module, this driver will be called "rt2500usb.ko".
+config RT2500USB_LEDS
+ bool "RT2500 leds support"
+ depends on RT2500USB
+ select RT2X00_LIB_LEDS
+ ---help---
+ This adds support for led triggers provided my mac80211.
+
config RT73USB
tristate "Ralink rt73 usb support"
- depends on RT2X00 && USB
+ depends on USB
select RT2X00_LIB_USB
select RT2X00_LIB_FIRMWARE
+ select CRC_ITU_T
---help---
This is an experimental driver for the Ralink rt73 wireless chip.
When compiled as a module, this driver will be called "rt73usb.ko".
+config RT73USB_LEDS
+ bool "RT73 leds support"
+ depends on RT73USB
+ select RT2X00_LIB_LEDS
+ ---help---
+ This adds support for led triggers provided my mac80211.
+
config RT2X00_LIB_DEBUGFS
bool "Ralink debugfs support"
depends on RT2X00_LIB && MAC80211_DEBUGFS
---help---
Enable debugging output for all rt2x00 modules
+endif
-rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o
+rt2x00lib-y += rt2x00dev.o
+rt2x00lib-y += rt2x00mac.o
+rt2x00lib-y += rt2x00config.o
+rt2x00lib-y += rt2x00queue.o
+rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
+rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o
+rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
+rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
-ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y)
- rt2x00lib-objs += rt2x00debug.o
-endif
-
-ifeq ($(CONFIG_RT2X00_LIB_RFKILL),y)
- rt2x00lib-objs += rt2x00rfkill.o
-endif
-
-ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y)
- rt2x00lib-objs += rt2x00firmware.o
-endif
-
-obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
-obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
-obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
-obj-$(CONFIG_RT2400PCI) += rt2400pci.o
-obj-$(CONFIG_RT2500PCI) += rt2500pci.o
-obj-$(CONFIG_RT61PCI) += rt61pci.o
-obj-$(CONFIG_RT2500USB) += rt2500usb.o
-obj-$(CONFIG_RT73USB) += rt73usb.o
+obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
+obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
+obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
+obj-$(CONFIG_RT2400PCI) += rt2400pci.o
+obj-$(CONFIG_RT2500PCI) += rt2500pci.o
+obj-$(CONFIG_RT61PCI) += rt61pci.o
+obj-$(CONFIG_RT2500USB) += rt2500usb.o
+obj-$(CONFIG_RT73USB) += rt73usb.o
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#define rt2400pci_rfkill_poll NULL
#endif /* CONFIG_RT2400PCI_RFKILL */
-/*
- * Configuration handlers.
- */
-static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev,
- __le32 *mac)
+#ifdef CONFIG_RT2400PCI_LEDS
+static void rt2400pci_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
{
- rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac,
- (2 * sizeof(__le32)));
-}
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ unsigned int enabled = brightness != LED_OFF;
+ unsigned int activity =
+ led->rt2x00dev->led_flags & LED_SUPPORT_ACTIVITY;
+ u32 reg;
-static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev,
- __le32 *bssid)
-{
- rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
- (2 * sizeof(__le32)));
+ rt2x00pci_register_read(led->rt2x00dev, LEDCSR, ®);
+
+ if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) {
+ rt2x00_set_field32(®, LEDCSR_LINK, enabled);
+ rt2x00_set_field32(®, LEDCSR_ACTIVITY, enabled && activity);
+ }
+
+ rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg);
}
+#else
+#define rt2400pci_led_brightness NULL
+#endif /* CONFIG_RT2400PCI_LEDS */
-static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
- const int tsf_sync)
+/*
+ * Configuration handlers.
+ */
+static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct rt2x00intf_conf *conf,
+ const unsigned int flags)
{
+ unsigned int bcn_preload;
u32 reg;
- rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+ if (flags & CONFIG_UPDATE_TYPE) {
+ /*
+ * Enable beacon config
+ */
+ bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+ rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®);
+ rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload);
+ rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
- /*
- * Enable beacon config
- */
- rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®);
- rt2x00_set_field32(®, BCNCSR1_PRELOAD,
- PREAMBLE + get_duration(IEEE80211_HEADER, 20));
- rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync);
+ rt2x00_set_field32(®, CSR14_TBCN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ }
- /*
- * Enable synchronisation.
- */
- rt2x00pci_register_read(rt2x00dev, CSR14, ®);
- rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
- rt2x00_set_field32(®, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON));
- rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
- rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ if (flags & CONFIG_UPDATE_MAC)
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR3,
+ conf->mac, sizeof(conf->mac));
+
+ if (flags & CONFIG_UPDATE_BSSID)
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR5,
+ conf->bssid, sizeof(conf->bssid));
}
-static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev,
- const int short_preamble,
- const int ack_timeout,
- const int ack_consume_time)
+static int rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp)
{
int preamble_mask;
u32 reg;
/*
* When short preamble is enabled, we should set bit 0x08
*/
- preamble_mask = short_preamble << 3;
+ preamble_mask = erp->short_preamble << 3;
rt2x00pci_register_read(rt2x00dev, TXCSR1, ®);
- rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, ack_timeout);
- rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, ack_consume_time);
+ rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT,
+ erp->ack_timeout);
+ rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME,
+ erp->ack_consume_time);
rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR2, ®);
rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84);
rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+ return 0;
}
static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
u8 r1;
u8 r4;
+ /*
+ * We should never come here because rt2x00lib is supposed
+ * to catch this and send us the correct antenna explicitely.
+ */
+ BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+ ant->tx == ANTENNA_SW_DIVERSITY);
+
rt2400pci_bbp_read(rt2x00dev, 4, &r4);
rt2400pci_bbp_read(rt2x00dev, 1, &r1);
case ANTENNA_A:
rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
break;
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
break;
}
case ANTENNA_A:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
break;
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
break;
}
}
static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
- const unsigned int flags,
- struct rt2x00lib_conf *libconf)
+ struct rt2x00lib_conf *libconf,
+ const unsigned int flags)
{
if (flags & CONFIG_UPDATE_PHYMODE)
rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
}
static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_tx_queue_params *params)
+ const int cw_min, const int cw_max)
{
u32 reg;
rt2x00pci_register_read(rt2x00dev, CSR11, ®);
- rt2x00_set_field32(®, CSR11_CWMIN, params->cw_min);
- rt2x00_set_field32(®, CSR11_CWMAX, params->cw_max);
+ rt2x00_set_field32(®, CSR11_CWMIN, cw_min);
+ rt2x00_set_field32(®, CSR11_CWMAX, cw_max);
rt2x00pci_register_write(rt2x00dev, CSR11, reg);
}
/*
- * LED functions.
- */
-static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, LEDCSR, ®);
-
- rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70);
- rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30);
- rt2x00_set_field32(®, LEDCSR_LINK,
- (rt2x00dev->led_mode != LED_MODE_ASUS));
- rt2x00_set_field32(®, LEDCSR_ACTIVITY,
- (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
- rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
-}
-
-static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, LEDCSR, ®);
- rt2x00_set_field32(®, LEDCSR_LINK, 0);
- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0);
- rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
-}
-
-/*
* Link tuning
*/
static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
* Initialization functions.
*/
static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry)
+ struct queue_entry *entry)
{
- __le32 *rxd = entry->priv;
+ struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
u32 word;
- rt2x00_desc_read(rxd, 2, &word);
- rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->ring->data_size);
- rt2x00_desc_write(rxd, 2, word);
+ rt2x00_desc_read(priv_rx->desc, 2, &word);
+ rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
+ entry->queue->data_size);
+ rt2x00_desc_write(priv_rx->desc, 2, word);
- rt2x00_desc_read(rxd, 1, &word);
- rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma);
- rt2x00_desc_write(rxd, 1, word);
+ rt2x00_desc_read(priv_rx->desc, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma);
+ rt2x00_desc_write(priv_rx->desc, 1, word);
- rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_desc_read(priv_rx->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(rxd, 0, word);
+ rt2x00_desc_write(priv_rx->desc, 0, word);
}
static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry)
+ struct queue_entry *entry)
{
- __le32 *txd = entry->priv;
+ struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
u32 word;
- rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma);
- rt2x00_desc_write(txd, 1, word);
+ rt2x00_desc_read(priv_tx->desc, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma);
+ rt2x00_desc_write(priv_tx->desc, 1, word);
- rt2x00_desc_read(txd, 2, &word);
- rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, entry->ring->data_size);
- rt2x00_desc_write(txd, 2, word);
+ rt2x00_desc_read(priv_tx->desc, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
+ entry->queue->data_size);
+ rt2x00_desc_write(priv_tx->desc, 2, word);
- rt2x00_desc_read(txd, 0, &word);
+ rt2x00_desc_read(priv_tx->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(txd, 0, word);
+ rt2x00_desc_write(priv_tx->desc, 0, word);
}
-static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
+static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
+ struct queue_entry_priv_pci_rx *priv_rx;
+ struct queue_entry_priv_pci_tx *priv_tx;
u32 reg;
/*
* Initialize registers.
*/
rt2x00pci_register_read(rt2x00dev, TXCSR2, ®);
- rt2x00_set_field32(®, TXCSR2_TXD_SIZE,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size);
- rt2x00_set_field32(®, TXCSR2_NUM_TXD,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
- rt2x00_set_field32(®, TXCSR2_NUM_ATIM,
- rt2x00dev->bcn[1].stats.limit);
- rt2x00_set_field32(®, TXCSR2_NUM_PRIO,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size);
+ rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit);
+ rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->bcn[1].limit);
+ rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+ priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR3, ®);
rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+ priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR5, ®);
rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+ priv_tx = rt2x00dev->bcn[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR4, ®);
rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER,
- rt2x00dev->bcn[1].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+ priv_tx = rt2x00dev->bcn[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR6, ®);
rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER,
- rt2x00dev->bcn[0].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
rt2x00pci_register_read(rt2x00dev, RXCSR1, ®);
rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
- rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit);
+ rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+ priv_rx = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RXCSR2, ®);
- rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER,
- rt2x00dev->rx->data_dma);
+ rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma);
rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
return 0;
(rt2x00dev->rx->data_size / 128));
rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, ®);
+ rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70);
+ rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30);
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+
rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
rt2x00pci_register_read(rt2x00dev, ARCSR0, ®);
rt2400pci_bbp_write(rt2x00dev, 30, 0x21);
rt2400pci_bbp_write(rt2x00dev, 31, 0x00);
- DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
for (i = 0; i < EEPROM_BBP_SIZE; i++) {
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
if (eeprom != 0xffff && eeprom != 0x0000) {
reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
- DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
- reg_id, value);
rt2400pci_bbp_write(rt2x00dev, reg_id, value);
}
}
- DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
return 0;
}
/*
* Initialize all registers.
*/
- if (rt2400pci_init_rings(rt2x00dev) ||
+ if (rt2400pci_init_queues(rt2x00dev) ||
rt2400pci_init_registers(rt2x00dev) ||
rt2400pci_init_bbp(rt2x00dev)) {
ERROR(rt2x00dev, "Register initialization failed.\n");
*/
rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
- /*
- * Enable LED
- */
- rt2400pci_enable_led(rt2x00dev);
-
return 0;
}
{
u32 reg;
- /*
- * Disable LED
- */
- rt2400pci_disable_led(rt2x00dev);
-
rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
/*
*/
static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txdata_entry_desc *desc,
+ struct txentry_desc *txdesc,
struct ieee80211_tx_control *control)
{
- struct skb_desc *skbdesc = get_skb_desc(skb);
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
u32 word;
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 3, &word);
- rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->signal);
rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5);
rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1);
- rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->service);
rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_REGNUM, 6);
rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1);
rt2x00_desc_write(txd, 3, word);
rt2x00_desc_read(txd, 4, &word);
- rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, txdesc->length_low);
rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8);
rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_BUSY, 1);
- rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_REGNUM, 7);
rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1);
rt2x00_desc_write(txd, 4, word);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
rt2x00_set_field32(&word, TXD_W0_VALID, 1);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
- test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK,
- test_bit(ENTRY_TXD_ACK, &desc->flags));
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
- test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_RTS,
- test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags));
- rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags &
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
* TX data initialization
*/
static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- unsigned int queue)
+ const unsigned int queue)
{
u32 reg;
- if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ if (queue == RT2X00_BCN_QUEUE_BEACON) {
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(®, CSR14_TBCN, 1);
rt2x00_set_field32(®, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
rt2x00_set_field32(®, TXCSR0_KICK_TX,
(queue == IEEE80211_TX_QUEUE_DATA1));
rt2x00_set_field32(®, TXCSR0_KICK_ATIM,
- (queue == IEEE80211_TX_QUEUE_AFTER_BEACON));
+ (queue == RT2X00_BCN_QUEUE_ATIM));
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
}
/*
* RX control handlers
*/
-static void rt2400pci_fill_rxdone(struct data_entry *entry,
- struct rxdata_entry_desc *desc)
+static void rt2400pci_fill_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
{
- __le32 *rxd = entry->priv;
+ struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
u32 word0;
u32 word2;
+ u32 word3;
- rt2x00_desc_read(rxd, 0, &word0);
- rt2x00_desc_read(rxd, 2, &word2);
+ rt2x00_desc_read(priv_rx->desc, 0, &word0);
+ rt2x00_desc_read(priv_rx->desc, 2, &word2);
+ rt2x00_desc_read(priv_rx->desc, 3, &word3);
- desc->flags = 0;
+ rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
- desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
- desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+ rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
/*
* Obtain the status about this packet.
+ * The signal is the PLCP value, and needs to be stripped
+ * of the preamble bit (0x08).
*/
- desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
- desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
- entry->ring->rt2x00dev->rssi_offset;
- desc->ofdm = 0;
- desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
+ rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL) & ~0x08;
+ rxdesc->signal_plcp = 1;
+ rxdesc->rssi = rt2x00_get_field32(word2, RXD_W3_RSSI) -
+ entry->queue->rt2x00dev->rssi_offset;
+ rxdesc->ofdm = 0;
+ rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+ rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
}
/*
* Interrupt functions.
*/
-static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
+ const enum ieee80211_tx_queue queue_idx)
{
- struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
- struct data_entry *entry;
- __le32 *txd;
+ struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+ struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry *entry;
+ struct txdone_entry_desc txdesc;
u32 word;
- int tx_status;
- int retry;
- while (!rt2x00_ring_empty(ring)) {
- entry = rt2x00_get_data_entry_done(ring);
- txd = entry->priv;
- rt2x00_desc_read(txd, 0, &word);
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ priv_tx = entry->priv_data;
+ rt2x00_desc_read(priv_tx->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID))
/*
* Obtain the status about this packet.
*/
- tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
- retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+ txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
- rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
+ rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
}
}
* 3 - Atim ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
- rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+ rt2400pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
/*
* 4 - Priority ring transmit done interrupt.
/*
* Store led mode, for correct led behaviour.
*/
- rt2x00dev->led_mode =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+#ifdef CONFIG_RT2400PCI_LEDS
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ switch (value) {
+ case LED_MODE_ASUS:
+ case LED_MODE_ALPHA:
+ case LED_MODE_DEFAULT:
+ rt2x00dev->led_flags = LED_SUPPORT_RADIO;
+ break;
+ case LED_MODE_TXRX_ACTIVITY:
+ rt2x00dev->led_flags =
+ LED_SUPPORT_RADIO | LED_SUPPORT_ACTIVITY;
+ break;
+ case LED_MODE_SIGNAL_STRENGTH:
+ rt2x00dev->led_flags = LED_SUPPORT_RADIO;
+ break;
+ }
+#endif /* CONFIG_RT2400PCI_LEDS */
/*
* Detect if this device has an hardware controlled radio.
/*
* Initialize hw_mode information.
*/
- spec->num_modes = 1;
- spec->num_rates = 4;
+ spec->supported_bands = SUPPORT_BAND_2GHZ;
+ spec->supported_rates = SUPPORT_RATE_CCK;
spec->tx_power_a = NULL;
spec->tx_power_bg = txpower;
spec->tx_power_default = DEFAULT_TXPOWER;
rt2400pci_probe_hw_mode(rt2x00dev);
/*
- * This device requires the beacon ring
+ * This device requires the atim queue
*/
- __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
/*
* Set the rssi offset.
/*
* Write configuration to register.
*/
- rt2400pci_config_cw(rt2x00dev, &rt2x00dev->tx->tx_params);
+ rt2400pci_config_cw(rt2x00dev,
+ rt2x00dev->tx->cw_min, rt2x00dev->tx->cw_max);
return 0;
}
return tsf;
}
-static void rt2400pci_reset_tsf(struct ieee80211_hw *hw)
+static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct rt2x00_intf *intf = vif_to_intf(control->vif);
+ struct queue_entry_priv_pci_tx *priv_tx;
+ struct skb_frame_desc *skbdesc;
+ u32 reg;
- rt2x00pci_register_write(rt2x00dev, CSR16, 0);
- rt2x00pci_register_write(rt2x00dev, CSR17, 0);
+ if (unlikely(!intf->beacon))
+ return -ENOBUFS;
+ priv_tx = intf->beacon->priv_data;
+
+ /*
+ * Fill in skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+ skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
+ skbdesc->data = skb->data;
+ skbdesc->data_len = skb->len;
+ skbdesc->desc = priv_tx->desc;
+ skbdesc->desc_len = intf->beacon->queue->desc_size;
+ skbdesc->entry = intf->beacon;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(®, CSR14_TBCN, 0);
+ rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+ /*
+ * mac80211 doesn't provide the control->queue variable
+ * for beacons. Set our own queue identification so
+ * it can be used during descriptor initialization.
+ */
+ control->queue = RT2X00_BCN_QUEUE_BEACON;
+ rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
+
+ /*
+ * Enable beacon generation.
+ * Write entire beacon with descriptor to register,
+ * and kick the beacon generator.
+ */
+ memcpy(priv_tx->data, skb->data, skb->len);
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+
+ return 0;
}
static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
.conf_tx = rt2400pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2400pci_get_tsf,
- .reset_tsf = rt2400pci_reset_tsf,
- .beacon_update = rt2x00pci_beacon_update,
+ .beacon_update = rt2400pci_beacon_update,
.tx_last_beacon = rt2400pci_tx_last_beacon,
};
.link_stats = rt2400pci_link_stats,
.reset_tuner = rt2400pci_reset_tuner,
.link_tuner = rt2400pci_link_tuner,
+ .led_brightness = rt2400pci_led_brightness,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt2400pci_kick_tx_queue,
.fill_rxdone = rt2400pci_fill_rxdone,
- .config_mac_addr = rt2400pci_config_mac_addr,
- .config_bssid = rt2400pci_config_bssid,
- .config_type = rt2400pci_config_type,
- .config_preamble = rt2400pci_config_preamble,
+ .config_intf = rt2400pci_config_intf,
+ .config_erp = rt2400pci_config_erp,
.config = rt2400pci_config,
};
+static const struct data_queue_desc rt2400pci_queue_rx = {
+ .entry_num = RX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = RXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_rx),
+};
+
+static const struct data_queue_desc rt2400pci_queue_tx = {
+ .entry_num = TX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+};
+
+static const struct data_queue_desc rt2400pci_queue_bcn = {
+ .entry_num = BEACON_ENTRIES,
+ .data_size = MGMT_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+};
+
+static const struct data_queue_desc rt2400pci_queue_atim = {
+ .entry_num = ATIM_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+};
+
static const struct rt2x00_ops rt2400pci_ops = {
.name = KBUILD_MODNAME,
- .rxd_size = RXD_DESC_SIZE,
- .txd_size = TXD_DESC_SIZE,
+ .max_sta_intf = 1,
+ .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .rx = &rt2400pci_queue_rx,
+ .tx = &rt2400pci_queue_tx,
+ .bcn = &rt2400pci_queue_bcn,
+ .atim = &rt2400pci_queue_atim,
.lib = &rt2400pci_rt2x00_ops,
.hw = &rt2400pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
* Word2
*/
#define RXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
-#define RXD_W2_SIGNAL FIELD32(0x00ff0000)
-#define RXD_W2_RSSI FIELD32(0xff000000)
+#define RXD_W2_BBR0 FIELD32(0x00ff0000)
+#define RXD_W2_SIGNAL FIELD32(0xff000000)
/*
* Word3
*/
-#define RXD_W3_BBR2 FIELD32(0x000000ff)
+#define RXD_W3_RSSI FIELD32(0x000000ff)
#define RXD_W3_BBR3 FIELD32(0x0000ff00)
#define RXD_W3_BBR4 FIELD32(0x00ff0000)
#define RXD_W3_BBR5 FIELD32(0xff000000)
#define RXD_W7_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to dscape value
- * and from dscape value to register value.
+ * Macro's for converting txpower from EEPROM to mac80211 value
+ * and from mac80211 value to register value.
* NOTE: Logics in rt2400pci for txpower are reversed
* compared to the other rt2x00 drivers. A higher txpower
* value means that the txpower must be lowered. This is
* important when converting the value coming from the
- * dscape stack to the rt2400 acceptable value.
+ * mac80211 stack to the rt2400 acceptable value.
*/
#define MIN_TXPOWER 31
#define MAX_TXPOWER 62
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#define rt2500pci_rfkill_poll NULL
#endif /* CONFIG_RT2500PCI_RFKILL */
-/*
- * Configuration handlers.
- */
-static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev,
- __le32 *mac)
+#ifdef CONFIG_RT2500PCI_LEDS
+static void rt2500pci_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
{
- rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac,
- (2 * sizeof(__le32)));
-}
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ unsigned int enabled = brightness != LED_OFF;
+ unsigned int activity =
+ led->rt2x00dev->led_flags & LED_SUPPORT_ACTIVITY;
+ u32 reg;
-static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev,
- __le32 *bssid)
-{
- rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
- (2 * sizeof(__le32)));
+ rt2x00pci_register_read(led->rt2x00dev, LEDCSR, ®);
+
+ if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) {
+ rt2x00_set_field32(®, LEDCSR_LINK, enabled);
+ rt2x00_set_field32(®, LEDCSR_ACTIVITY, enabled && activity);
+ }
+
+ rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg);
}
+#else
+#define rt2500pci_led_brightness NULL
+#endif /* CONFIG_RT2500PCI_LEDS */
-static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
- const int tsf_sync)
+/*
+ * Configuration handlers.
+ */
+static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct rt2x00intf_conf *conf,
+ const unsigned int flags)
{
+ struct data_queue *queue =
+ rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON);
+ unsigned int bcn_preload;
u32 reg;
- rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+ if (flags & CONFIG_UPDATE_TYPE) {
+ /*
+ * Enable beacon config
+ */
+ bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+ rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®);
+ rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload);
+ rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, queue->cw_min);
+ rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
- /*
- * Enable beacon config
- */
- rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®);
- rt2x00_set_field32(®, BCNCSR1_PRELOAD,
- PREAMBLE + get_duration(IEEE80211_HEADER, 20));
- rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN,
- rt2x00lib_get_ring(rt2x00dev,
- IEEE80211_TX_QUEUE_BEACON)
- ->tx_params.cw_min);
- rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync);
+ rt2x00_set_field32(®, CSR14_TBCN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ }
- /*
- * Enable synchronisation.
- */
- rt2x00pci_register_read(rt2x00dev, CSR14, ®);
- rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
- rt2x00_set_field32(®, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON));
- rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
- rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ if (flags & CONFIG_UPDATE_MAC)
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR3,
+ conf->mac, sizeof(conf->mac));
+
+ if (flags & CONFIG_UPDATE_BSSID)
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR5,
+ conf->bssid, sizeof(conf->bssid));
}
-static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev,
- const int short_preamble,
- const int ack_timeout,
- const int ack_consume_time)
+static int rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp)
{
int preamble_mask;
u32 reg;
/*
* When short preamble is enabled, we should set bit 0x08
*/
- preamble_mask = short_preamble << 3;
+ preamble_mask = erp->short_preamble << 3;
rt2x00pci_register_read(rt2x00dev, TXCSR1, ®);
- rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, ack_timeout);
- rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, ack_consume_time);
+ rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT,
+ erp->ack_timeout);
+ rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME,
+ erp->ack_consume_time);
rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR2, ®);
rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84);
rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+ return 0;
}
static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
u8 r14;
u8 r2;
+ /*
+ * We should never come here because rt2x00lib is supposed
+ * to catch this and send us the correct antenna explicitely.
+ */
+ BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+ ant->tx == ANTENNA_SW_DIVERSITY);
+
rt2x00pci_register_read(rt2x00dev, BBPCSR1, ®);
rt2500pci_bbp_read(rt2x00dev, 14, &r14);
rt2500pci_bbp_read(rt2x00dev, 2, &r2);
rt2x00_set_field32(®, BBPCSR1_CCK, 0);
rt2x00_set_field32(®, BBPCSR1_OFDM, 0);
break;
- case ANTENNA_HW_DIVERSITY:
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
rt2x00_set_field32(®, BBPCSR1_CCK, 2);
rt2x00_set_field32(®, BBPCSR1_OFDM, 2);
case ANTENNA_A:
rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
break;
- case ANTENNA_HW_DIVERSITY:
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
break;
}
}
static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
- const unsigned int flags,
- struct rt2x00lib_conf *libconf)
+ struct rt2x00lib_conf *libconf,
+ const unsigned int flags)
{
if (flags & CONFIG_UPDATE_PHYMODE)
rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
}
/*
- * LED functions.
- */
-static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, LEDCSR, ®);
-
- rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70);
- rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30);
- rt2x00_set_field32(®, LEDCSR_LINK,
- (rt2x00dev->led_mode != LED_MODE_ASUS));
- rt2x00_set_field32(®, LEDCSR_ACTIVITY,
- (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
- rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
-}
-
-static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, LEDCSR, ®);
- rt2x00_set_field32(®, LEDCSR_LINK, 0);
- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0);
- rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
-}
-
-/*
* Link tuning
*/
static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev,
/*
* To prevent collisions with MAC ASIC on chipsets
* up to version C the link tuning should halt after 20
- * seconds.
+ * seconds while being associated.
*/
if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
+ rt2x00dev->intf_associated &&
rt2x00dev->link.count > 20)
return;
/*
* Chipset versions C and lower should directly continue
- * to the dynamic CCA tuning.
+ * to the dynamic CCA tuning. Chipset version D and higher
+ * should go straight to dynamic CCA tuning when they
+ * are not associated.
*/
- if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D)
+ if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D ||
+ !rt2x00dev->intf_associated)
goto dynamic_cca_tune;
/*
* Initialization functions.
*/
static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry)
+ struct queue_entry *entry)
{
- __le32 *rxd = entry->priv;
+ struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
u32 word;
- rt2x00_desc_read(rxd, 1, &word);
- rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma);
- rt2x00_desc_write(rxd, 1, word);
+ rt2x00_desc_read(priv_rx->desc, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma);
+ rt2x00_desc_write(priv_rx->desc, 1, word);
- rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_desc_read(priv_rx->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(rxd, 0, word);
+ rt2x00_desc_write(priv_rx->desc, 0, word);
}
static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry)
+ struct queue_entry *entry)
{
- __le32 *txd = entry->priv;
+ struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
u32 word;
- rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma);
- rt2x00_desc_write(txd, 1, word);
+ rt2x00_desc_read(priv_tx->desc, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma);
+ rt2x00_desc_write(priv_tx->desc, 1, word);
- rt2x00_desc_read(txd, 0, &word);
+ rt2x00_desc_read(priv_tx->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(txd, 0, word);
+ rt2x00_desc_write(priv_tx->desc, 0, word);
}
-static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev)
+static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
+ struct queue_entry_priv_pci_rx *priv_rx;
+ struct queue_entry_priv_pci_tx *priv_tx;
u32 reg;
/*
* Initialize registers.
*/
rt2x00pci_register_read(rt2x00dev, TXCSR2, ®);
- rt2x00_set_field32(®, TXCSR2_TXD_SIZE,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size);
- rt2x00_set_field32(®, TXCSR2_NUM_TXD,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
- rt2x00_set_field32(®, TXCSR2_NUM_ATIM,
- rt2x00dev->bcn[1].stats.limit);
- rt2x00_set_field32(®, TXCSR2_NUM_PRIO,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size);
+ rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit);
+ rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->bcn[1].limit);
+ rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+ priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR3, ®);
rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+ priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR5, ®);
rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+ priv_tx = rt2x00dev->bcn[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR4, ®);
rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER,
- rt2x00dev->bcn[1].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+ priv_tx = rt2x00dev->bcn[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR6, ®);
rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER,
- rt2x00dev->bcn[0].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
rt2x00pci_register_read(rt2x00dev, RXCSR1, ®);
rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
- rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit);
+ rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+ priv_rx = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RXCSR2, ®);
- rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER,
- rt2x00dev->rx->data_dma);
+ rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma);
rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
return 0;
rt2x00_set_field32(®, CSR11_CW_SELECT, 0);
rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, ®);
+ rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70);
+ rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30);
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+
rt2x00pci_register_write(rt2x00dev, CNT3, 0);
rt2x00pci_register_read(rt2x00dev, TXCSR8, ®);
rt2500pci_bbp_write(rt2x00dev, 61, 0x6d);
rt2500pci_bbp_write(rt2x00dev, 62, 0x10);
- DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
for (i = 0; i < EEPROM_BBP_SIZE; i++) {
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
if (eeprom != 0xffff && eeprom != 0x0000) {
reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
- DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
- reg_id, value);
rt2500pci_bbp_write(rt2x00dev, reg_id, value);
}
}
- DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
return 0;
}
/*
* Initialize all registers.
*/
- if (rt2500pci_init_rings(rt2x00dev) ||
+ if (rt2500pci_init_queues(rt2x00dev) ||
rt2500pci_init_registers(rt2x00dev) ||
rt2500pci_init_bbp(rt2x00dev)) {
ERROR(rt2x00dev, "Register initialization failed.\n");
*/
rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
- /*
- * Enable LED
- */
- rt2500pci_enable_led(rt2x00dev);
-
return 0;
}
{
u32 reg;
- /*
- * Disable LED
- */
- rt2500pci_disable_led(rt2x00dev);
-
rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
/*
*/
static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txdata_entry_desc *desc,
+ struct txentry_desc *txdesc,
struct ieee80211_tx_control *control)
{
- struct skb_desc *skbdesc = get_skb_desc(skb);
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
u32 word;
*/
rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
- rt2x00_set_field32(&word, TXD_W2_AIFS, desc->aifs);
- rt2x00_set_field32(&word, TXD_W2_CWMIN, desc->cw_min);
- rt2x00_set_field32(&word, TXD_W2_CWMAX, desc->cw_max);
+ rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs);
+ rt2x00_set_field32(&word, TXD_W2_CWMIN, txdesc->cw_min);
+ rt2x00_set_field32(&word, TXD_W2_CWMAX, txdesc->cw_max);
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 3, &word);
- rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal);
- rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service);
- rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, desc->length_low);
- rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->signal);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->service);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, txdesc->length_low);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_desc_write(txd, 3, word);
rt2x00_desc_read(txd, 10, &word);
rt2x00_set_field32(&word, TXD_W10_RTS,
- test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags));
+ test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags));
rt2x00_desc_write(txd, 10, word);
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
rt2x00_set_field32(&word, TXD_W0_VALID, 1);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
- test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK,
- test_bit(ENTRY_TXD_ACK, &desc->flags));
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
- test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_OFDM,
- test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1);
- rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags &
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
* TX data initialization
*/
static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- unsigned int queue)
+ const unsigned int queue)
{
u32 reg;
- if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ if (queue == RT2X00_BCN_QUEUE_BEACON) {
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(®, CSR14_TBCN, 1);
rt2x00_set_field32(®, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
rt2x00_set_field32(®, TXCSR0_KICK_TX,
(queue == IEEE80211_TX_QUEUE_DATA1));
rt2x00_set_field32(®, TXCSR0_KICK_ATIM,
- (queue == IEEE80211_TX_QUEUE_AFTER_BEACON));
+ (queue == RT2X00_BCN_QUEUE_ATIM));
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
}
/*
* RX control handlers
*/
-static void rt2500pci_fill_rxdone(struct data_entry *entry,
- struct rxdata_entry_desc *desc)
+static void rt2500pci_fill_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
{
- __le32 *rxd = entry->priv;
+ struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
u32 word0;
u32 word2;
- rt2x00_desc_read(rxd, 0, &word0);
- rt2x00_desc_read(rxd, 2, &word2);
+ rt2x00_desc_read(priv_rx->desc, 0, &word0);
+ rt2x00_desc_read(priv_rx->desc, 2, &word2);
- desc->flags = 0;
+ rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
- desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
- desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
-
- desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
- desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
- entry->ring->rt2x00dev->rssi_offset;
- desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
- desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
+ rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ * When frame was received with an OFDM bitrate,
+ * the signal is the PLCP value. If it was received with
+ * a CCK bitrate the signal is the rate in 100kbit/s.
+ */
+ rxdesc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+ rxdesc->signal_plcp = rxdesc->ofdm;
+ rxdesc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+ entry->queue->rt2x00dev->rssi_offset;
+ rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+ rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
}
/*
* Interrupt functions.
*/
-static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
+ const enum ieee80211_tx_queue queue_idx)
{
- struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
- struct data_entry *entry;
- __le32 *txd;
+ struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+ struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry *entry;
+ struct txdone_entry_desc txdesc;
u32 word;
- int tx_status;
- int retry;
- while (!rt2x00_ring_empty(ring)) {
- entry = rt2x00_get_data_entry_done(ring);
- txd = entry->priv;
- rt2x00_desc_read(txd, 0, &word);
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ priv_tx = entry->priv_data;
+ rt2x00_desc_read(priv_tx->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID))
/*
* Obtain the status about this packet.
*/
- tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
- retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+ txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
- rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
+ rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
}
}
* 3 - Atim ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
- rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+ rt2500pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
/*
* 4 - Priority ring transmit done interrupt.
/*
* Store led mode, for correct led behaviour.
*/
- rt2x00dev->led_mode =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+#ifdef CONFIG_RT2500PCI_LEDS
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ switch (value) {
+ case LED_MODE_ASUS:
+ case LED_MODE_ALPHA:
+ case LED_MODE_DEFAULT:
+ rt2x00dev->led_flags = LED_SUPPORT_RADIO;
+ break;
+ case LED_MODE_TXRX_ACTIVITY:
+ rt2x00dev->led_flags =
+ LED_SUPPORT_RADIO | LED_SUPPORT_ACTIVITY;
+ break;
+ case LED_MODE_SIGNAL_STRENGTH:
+ rt2x00dev->led_flags = LED_SUPPORT_RADIO;
+ break;
+ }
+#endif /* CONFIG_RT2500PCI_LEDS */
/*
* Detect if this device has an hardware controlled radio.
/*
* Initialize hw_mode information.
*/
- spec->num_modes = 2;
- spec->num_rates = 12;
+ spec->supported_bands = SUPPORT_BAND_2GHZ;
+ spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
spec->tx_power_a = NULL;
spec->tx_power_bg = txpower;
spec->tx_power_default = DEFAULT_TXPOWER;
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
spec->channels = rf_vals_bg_2525e;
} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5222);
spec->channels = rf_vals_5222;
- spec->num_modes = 3;
}
}
rt2500pci_probe_hw_mode(rt2x00dev);
/*
- * This device requires the beacon ring
+ * This device requires the atim queue
*/
- __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
/*
* Set the rssi offset.
return tsf;
}
-static void rt2500pci_reset_tsf(struct ieee80211_hw *hw)
+static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct rt2x00_intf *intf = vif_to_intf(control->vif);
+ struct queue_entry_priv_pci_tx *priv_tx;
+ struct skb_frame_desc *skbdesc;
+ u32 reg;
- rt2x00pci_register_write(rt2x00dev, CSR16, 0);
- rt2x00pci_register_write(rt2x00dev, CSR17, 0);
+ if (unlikely(!intf->beacon))
+ return -ENOBUFS;
+
+ priv_tx = intf->beacon->priv_data;
+
+ /*
+ * Fill in skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+ skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
+ skbdesc->data = skb->data;
+ skbdesc->data_len = skb->len;
+ skbdesc->desc = priv_tx->desc;
+ skbdesc->desc_len = intf->beacon->queue->desc_size;
+ skbdesc->entry = intf->beacon;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(®, CSR14_TBCN, 0);
+ rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+ /*
+ * mac80211 doesn't provide the control->queue variable
+ * for beacons. Set our own queue identification so
+ * it can be used during descriptor initialization.
+ */
+ control->queue = RT2X00_BCN_QUEUE_BEACON;
+ rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
+
+ /*
+ * Enable beacon generation.
+ * Write entire beacon with descriptor to register,
+ * and kick the beacon generator.
+ */
+ memcpy(priv_tx->data, skb->data, skb->len);
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+
+ return 0;
}
static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2500pci_get_tsf,
- .reset_tsf = rt2500pci_reset_tsf,
- .beacon_update = rt2x00pci_beacon_update,
+ .beacon_update = rt2500pci_beacon_update,
.tx_last_beacon = rt2500pci_tx_last_beacon,
};
.link_stats = rt2500pci_link_stats,
.reset_tuner = rt2500pci_reset_tuner,
.link_tuner = rt2500pci_link_tuner,
+ .led_brightness = rt2500pci_led_brightness,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt2500pci_kick_tx_queue,
.fill_rxdone = rt2500pci_fill_rxdone,
- .config_mac_addr = rt2500pci_config_mac_addr,
- .config_bssid = rt2500pci_config_bssid,
- .config_type = rt2500pci_config_type,
- .config_preamble = rt2500pci_config_preamble,
+ .config_intf = rt2500pci_config_intf,
+ .config_erp = rt2500pci_config_erp,
.config = rt2500pci_config,
};
+static const struct data_queue_desc rt2500pci_queue_rx = {
+ .entry_num = RX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = RXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_rx),
+};
+
+static const struct data_queue_desc rt2500pci_queue_tx = {
+ .entry_num = TX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+};
+
+static const struct data_queue_desc rt2500pci_queue_bcn = {
+ .entry_num = BEACON_ENTRIES,
+ .data_size = MGMT_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+};
+
+static const struct data_queue_desc rt2500pci_queue_atim = {
+ .entry_num = ATIM_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+};
+
static const struct rt2x00_ops rt2500pci_ops = {
.name = KBUILD_MODNAME,
- .rxd_size = RXD_DESC_SIZE,
- .txd_size = TXD_DESC_SIZE,
+ .max_sta_intf = 1,
+ .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .rx = &rt2500pci_queue_rx,
+ .tx = &rt2500pci_queue_tx,
+ .bcn = &rt2500pci_queue_bcn,
+ .atim = &rt2500pci_queue_atim,
.lib = &rt2500pci_rt2x00_ops,
.hw = &rt2500pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#define RXD_W10_DROP FIELD32(0x00000001)
/*
- * Macro's for converting txpower from EEPROM to dscape value
- * and from dscape value to register value.
+ * Macro's for converting txpower from EEPROM to mac80211 value
+ * and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
#define MAX_TXPOWER 31
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-/*
- * Configuration handlers.
- */
-static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev,
- __le32 *mac)
+#ifdef CONFIG_RT2500USB_LEDS
+static void rt2500usb_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
{
- rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
- (3 * sizeof(__le16)));
-}
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ unsigned int enabled = brightness != LED_OFF;
+ unsigned int activity =
+ led->rt2x00dev->led_flags & LED_SUPPORT_ACTIVITY;
-static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev,
- __le32 *bssid)
-{
- rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid,
- (3 * sizeof(__le16)));
+ if (in_atomic()) {
+ NOTICE(led->rt2x00dev,
+ "Ignoring LED brightness command for led %d\n",
+ led->type);
+ return;
+ }
+
+ if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) {
+ rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
+ MAC_CSR20_LINK, enabled);
+ rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
+ MAC_CSR20_ACTIVITY, enabled && activity);
+ }
+
+ rt2500usb_register_write(led->rt2x00dev, MAC_CSR20,
+ led->rt2x00dev->led_mcu_reg);
}
+#else
+#define rt2500usb_led_brightness NULL
+#endif /* CONFIG_RT2500USB_LEDS */
-static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
- const int tsf_sync)
+/*
+ * Configuration handlers.
+ */
+static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct rt2x00intf_conf *conf,
+ const unsigned int flags)
{
+ unsigned int bcn_preload;
u16 reg;
- rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+ if (flags & CONFIG_UPDATE_TYPE) {
+ /*
+ * Enable beacon config
+ */
+ bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®);
+ rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6);
+ rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW,
+ 2 * (conf->type != IEEE80211_IF_TYPE_STA));
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg);
- /*
- * Enable beacon config
- */
- rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®);
- rt2x00_set_field16(®, TXRX_CSR20_OFFSET,
- (PREAMBLE + get_duration(IEEE80211_HEADER, 20)) >> 6);
- if (type == IEEE80211_IF_TYPE_STA)
- rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0);
- else
- rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg);
+ /*
+ * Enable synchronisation.
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®);
+ rt2x00_set_field16(®, TXRX_CSR18_OFFSET, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, conf->sync);
+ rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ }
- /*
- * Enable synchronisation.
- */
- rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®);
- rt2x00_set_field16(®, TXRX_CSR18_OFFSET, 0);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+ if (flags & CONFIG_UPDATE_MAC)
+ rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, conf->mac,
+ (3 * sizeof(__le16)));
- rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
- rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
- rt2x00_set_field16(®, TXRX_CSR19_TBCN,
- (tsf_sync == TSF_SYNC_BEACON));
- rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
- rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, tsf_sync);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ if (flags & CONFIG_UPDATE_BSSID)
+ rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, conf->bssid,
+ (3 * sizeof(__le16)));
}
-static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev,
- const int short_preamble,
- const int ack_timeout,
- const int ack_consume_time)
+static int rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp)
{
u16 reg;
/*
- * When in atomic context, reschedule and let rt2x00lib
- * call this function again.
+ * When in atomic context, we should let rt2x00lib
+ * try this configuration again later.
*/
- if (in_atomic()) {
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
- return;
- }
+ if (in_atomic())
+ return -EAGAIN;
rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®);
- rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, ack_timeout);
+ rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, erp->ack_timeout);
rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®);
rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE,
- !!short_preamble);
+ !!erp->short_preamble);
rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
+
+ return 0;
}
static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
- const int phymode,
const int basic_rate_mask)
{
rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
-
- if (phymode == HWMODE_B) {
- rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b);
- rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040);
- } else {
- rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0005);
- rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x016c);
- }
}
static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
u16 csr5;
u16 csr6;
+ /*
+ * We should never come here because rt2x00lib is supposed
+ * to catch this and send us the correct antenna explicitely.
+ */
+ BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+ ant->tx == ANTENNA_SW_DIVERSITY);
+
rt2500usb_bbp_read(rt2x00dev, 2, &r2);
rt2500usb_bbp_read(rt2x00dev, 14, &r14);
rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5);
rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0);
rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0);
break;
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2);
rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 2);
case ANTENNA_A:
rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
break;
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
break;
}
u16 reg;
rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, libconf->sifs);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR12, libconf->eifs);
rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®);
rt2x00_set_field16(®, TXRX_CSR18_INTERVAL,
}
static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
- const unsigned int flags,
- struct rt2x00lib_conf *libconf)
+ struct rt2x00lib_conf *libconf,
+ const unsigned int flags)
{
if (flags & CONFIG_UPDATE_PHYMODE)
- rt2500usb_config_phymode(rt2x00dev, libconf->phymode,
- libconf->basic_rates);
+ rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates);
if (flags & CONFIG_UPDATE_CHANNEL)
rt2500usb_config_channel(rt2x00dev, &libconf->rf,
libconf->conf->power_level);
}
/*
- * LED functions.
- */
-static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev)
-{
- u16 reg;
-
- rt2500usb_register_read(rt2x00dev, MAC_CSR21, ®);
- rt2x00_set_field16(®, MAC_CSR21_ON_PERIOD, 70);
- rt2x00_set_field16(®, MAC_CSR21_OFF_PERIOD, 30);
- rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
-
- rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®);
- rt2x00_set_field16(®, MAC_CSR20_LINK,
- (rt2x00dev->led_mode != LED_MODE_ASUS));
- rt2x00_set_field16(®, MAC_CSR20_ACTIVITY,
- (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
- rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
-}
-
-static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev)
-{
- u16 reg;
-
- rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®);
- rt2x00_set_field16(®, MAC_CSR20_LINK, 0);
- rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0);
- rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
-}
-
-/*
* Link tuning
*/
static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev,
u8 low_bound;
/*
+ * Read current r17 value, as well as the sensitivity values
+ * for the r17 register.
+ */
+ rt2500usb_bbp_read(rt2x00dev, 17, &r17);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound);
+ up_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER);
+ low_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCLOWER);
+
+ /*
+ * If we are not associated, we should go straight to the
+ * dynamic CCA tuning.
+ */
+ if (!rt2x00dev->intf_associated)
+ goto dynamic_cca_tune;
+
+ /*
* Determine the BBP tuning threshold and correctly
* set BBP 24, 25 and 61.
*/
rt2500usb_bbp_write(rt2x00dev, 61, r61);
/*
- * Read current r17 value, as well as the sensitivity values
- * for the r17 register.
- */
- rt2500usb_bbp_read(rt2x00dev, 17, &r17);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens);
-
- /*
* A too low RSSI will cause too much false CCA which will
* then corrupt the R17 tuning. To remidy this the tuning should
* be stopped (While making sure the R17 value will not exceed limits)
* Leave short or middle distance condition, restore r17
* to the dynamic tuning range.
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound);
- vgc_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER);
-
low_bound = 0x32;
- if (rssi >= -77)
- up_bound = vgc_bound;
- else
- up_bound = vgc_bound - (-77 - rssi);
+ if (rssi < -77)
+ up_bound -= (-77 - rssi);
if (up_bound < low_bound)
up_bound = low_bound;
if (r17 > up_bound) {
rt2500usb_bbp_write(rt2x00dev, 17, up_bound);
rt2x00dev->link.vgc_level = up_bound;
- } else if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
+ return;
+ }
+
+dynamic_cca_tune:
+
+ /*
+ * R17 is inside the dynamic tuning range,
+ * start tuning the link based on the false cca counter.
+ */
+ if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
rt2500usb_bbp_write(rt2x00dev, 17, ++r17);
rt2x00dev->link.vgc_level = r17;
} else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) {
rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0);
rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2500usb_register_read(rt2x00dev, MAC_CSR21, ®);
+ rt2x00_set_field16(®, MAC_CSR21_ON_PERIOD, 70);
+ rt2x00_set_field16(®, MAC_CSR21_OFF_PERIOD, 30);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
+
rt2500usb_register_read(rt2x00dev, TXRX_CSR5, ®);
rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0, 13);
rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0_VALID, 1);
rt2500usb_bbp_write(rt2x00dev, 62, 0x10);
rt2500usb_bbp_write(rt2x00dev, 75, 0xff);
- DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
for (i = 0; i < EEPROM_BBP_SIZE; i++) {
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
if (eeprom != 0xffff && eeprom != 0x0000) {
reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
- DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
- reg_id, value);
rt2500usb_bbp_write(rt2x00dev, reg_id, value);
}
}
- DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
return 0;
}
return -EIO;
}
- /*
- * Enable LED
- */
- rt2500usb_enable_led(rt2x00dev);
-
return 0;
}
static void rt2500usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
- /*
- * Disable LED
- */
- rt2500usb_disable_led(rt2x00dev);
-
rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x2121);
rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x2121);
*/
static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txdata_entry_desc *desc,
+ struct txentry_desc *txdesc,
struct ieee80211_tx_control *control)
{
- struct skb_desc *skbdesc = get_skb_desc(skb);
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
u32 word;
*/
rt2x00_desc_read(txd, 1, &word);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
- rt2x00_set_field32(&word, TXD_W1_AIFS, desc->aifs);
- rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
- rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
- rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
- rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
- rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
- rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
- test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK,
- test_bit(ENTRY_TXD_ACK, &desc->flags));
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
- test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_OFDM,
- test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
!!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT));
- rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word);
* TX data initialization
*/
static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- unsigned int queue)
+ const unsigned int queue)
{
u16 reg;
- if (queue != IEEE80211_TX_QUEUE_BEACON)
+ if (queue != RT2X00_BCN_QUEUE_BEACON)
return;
rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
+ rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1);
rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1);
/*
* Beacon generation will fail initially.
/*
* RX control handlers
*/
-static void rt2500usb_fill_rxdone(struct data_entry *entry,
- struct rxdata_entry_desc *desc)
+static void rt2500usb_fill_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
{
- struct skb_desc *skbdesc = get_skb_desc(entry->skb);
- struct urb *urb = entry->priv;
- __le32 *rxd = (__le32 *)(entry->skb->data +
- (urb->actual_length - entry->ring->desc_size));
+ struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ __le32 *rxd =
+ (__le32 *)(entry->skb->data +
+ (priv_rx->urb->actual_length - entry->queue->desc_size));
+ unsigned int offset = entry->queue->desc_size + 2;
u32 word0;
u32 word1;
+ /*
+ * Copy descriptor to the available headroom inside the skbuffer.
+ */
+ skb_push(entry->skb, offset);
+ memcpy(entry->skb->data, rxd, entry->queue->desc_size);
+ rxd = (__le32 *)entry->skb->data;
+
+ /*
+ * The descriptor is now aligned to 4 bytes and thus it is
+ * now safe to read it on all architectures.
+ */
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1);
- desc->flags = 0;
+ rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
- desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
- desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+ rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
/*
* Obtain the status about this packet.
+ * When frame was received with an OFDM bitrate,
+ * the signal is the PLCP value. If it was received with
+ * a CCK bitrate the signal is the rate in 100kbit/s.
*/
- desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
- entry->ring->rt2x00dev->rssi_offset;
- desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
- desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
+ rxdesc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ rxdesc->signal_plcp = rxdesc->ofdm;
+ rxdesc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
+ entry->queue->rt2x00dev->rssi_offset;
+ rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+ rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
+
+ /*
+ * Adjust the skb memory window to the frame boundaries.
+ */
+ skb_pull(entry->skb, offset);
+ skb_trim(entry->skb, rxdesc->size);
/*
* Set descriptor and data pointer.
*/
- skbdesc->desc = entry->skb->data + desc->size;
- skbdesc->desc_len = entry->ring->desc_size;
skbdesc->data = entry->skb->data;
- skbdesc->data_len = desc->size;
+ skbdesc->data_len = rxdesc->size;
+ skbdesc->desc = rxd;
+ skbdesc->desc_len = entry->queue->desc_size;
}
/*
*/
static void rt2500usb_beacondone(struct urb *urb)
{
- struct data_entry *entry = (struct data_entry *)urb->context;
- struct data_ring *ring = entry->ring;
+ struct queue_entry *entry = (struct queue_entry *)urb->context;
+ struct queue_entry_priv_usb_bcn *priv_bcn = entry->priv_data;
- if (!test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags))
+ if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags))
return;
/*
* Otherwise we should free the sk_buffer, the device
* should be doing the rest of the work now.
*/
- if (ring->index == 1) {
- rt2x00_ring_index_done_inc(ring);
- entry = rt2x00_get_data_entry(ring);
- usb_submit_urb(entry->priv, GFP_ATOMIC);
- rt2x00_ring_index_inc(ring);
- } else if (ring->index_done == 1) {
- entry = rt2x00_get_data_entry_done(ring);
- if (entry->skb) {
- dev_kfree_skb(entry->skb);
- entry->skb = NULL;
- }
- rt2x00_ring_index_done_inc(ring);
+ if (priv_bcn->guardian_urb == urb) {
+ usb_submit_urb(priv_bcn->urb, GFP_ATOMIC);
+ } else if (priv_bcn->urb == urb) {
+ dev_kfree_skb(entry->skb);
+ entry->skb = NULL;
}
}
{
u16 word;
u8 *mac;
+ u8 bbp;
rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
EEPROM(rt2x00dev, "BBPtune: 0x%04x\n", word);
}
+ /*
+ * Switch lower vgc bound to current BBP R17 value,
+ * lower the value a bit for better quality.
+ */
+ rt2500usb_bbp_read(rt2x00dev, 17, &bbp);
+ bbp -= 6;
+
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
}
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word);
EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
+ } else {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word);
/*
* Store led mode, for correct led behaviour.
*/
- rt2x00dev->led_mode =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+#ifdef CONFIG_RT2500USB_LEDS
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ switch (value) {
+ case LED_MODE_ASUS:
+ case LED_MODE_ALPHA:
+ case LED_MODE_DEFAULT:
+ rt2x00dev->led_flags = LED_SUPPORT_RADIO;
+ break;
+ case LED_MODE_TXRX_ACTIVITY:
+ rt2x00dev->led_flags =
+ LED_SUPPORT_RADIO | LED_SUPPORT_ACTIVITY;
+ break;
+ case LED_MODE_SIGNAL_STRENGTH:
+ rt2x00dev->led_flags = LED_SUPPORT_RADIO;
+ break;
+ }
+
+ /*
+ * Store the current led register value, we need it later
+ * in set_brightness but that is called in irq context which
+ * means we can't use rt2500usb_register_read() at that time.
+ */
+ rt2500usb_register_read(rt2x00dev, MAC_CSR20, &rt2x00dev->led_mcu_reg);
+#endif /* CONFIG_RT2500USB_LEDS */
/*
* Check if the BBP tuning should be disabled.
/*
* Initialize hw_mode information.
*/
- spec->num_modes = 2;
- spec->num_rates = 12;
+ spec->supported_bands = SUPPORT_BAND_2GHZ;
+ spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
spec->tx_power_a = NULL;
spec->tx_power_bg = txpower;
spec->tx_power_default = DEFAULT_TXPOWER;
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
spec->channels = rf_vals_bg_2525e;
} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5222);
spec->channels = rf_vals_5222;
- spec->num_modes = 3;
}
}
rt2500usb_probe_hw_mode(rt2x00dev);
/*
- * This device requires the beacon ring
+ * This device requires the atim queue
*/
- __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
/*
* Set the rssi offset.
struct ieee80211_tx_control *control)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct usb_device *usb_dev =
- interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
- struct skb_desc *desc;
- struct data_ring *ring;
- struct data_entry *beacon;
- struct data_entry *guardian;
+ struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
+ struct rt2x00_intf *intf = vif_to_intf(control->vif);
+ struct queue_entry_priv_usb_bcn *priv_bcn;
+ struct skb_frame_desc *skbdesc;
int pipe = usb_sndbulkpipe(usb_dev, 1);
int length;
+ u16 reg;
+
+ if (unlikely(!intf->beacon))
+ return -ENOBUFS;
+
+ priv_bcn = intf->beacon->priv_data;
/*
- * Just in case the ieee80211 doesn't set this,
- * but we need this queue set for the descriptor
- * initialization.
+ * Add the descriptor in front of the skb.
*/
- control->queue = IEEE80211_TX_QUEUE_BEACON;
- ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+ skb_push(skb, intf->beacon->queue->desc_size);
+ memset(skb->data, 0, intf->beacon->queue->desc_size);
/*
- * Obtain 2 entries, one for the guardian byte,
- * the second for the actual beacon.
+ * Fill in skb descriptor
*/
- guardian = rt2x00_get_data_entry(ring);
- rt2x00_ring_index_inc(ring);
- beacon = rt2x00_get_data_entry(ring);
+ skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+ skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
+ skbdesc->data = skb->data + intf->beacon->queue->desc_size;
+ skbdesc->data_len = skb->len - intf->beacon->queue->desc_size;
+ skbdesc->desc = skb->data;
+ skbdesc->desc_len = intf->beacon->queue->desc_size;
+ skbdesc->entry = intf->beacon;
/*
- * Add the descriptor in front of the skb.
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
*/
- skb_push(skb, ring->desc_size);
- memset(skb->data, 0, ring->desc_size);
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
/*
- * Fill in skb descriptor
+ * mac80211 doesn't provide the control->queue variable
+ * for beacons. Set our own queue identification so
+ * it can be used during descriptor initialization.
*/
- desc = get_skb_desc(skb);
- desc->desc_len = ring->desc_size;
- desc->data_len = skb->len - ring->desc_size;
- desc->desc = skb->data;
- desc->data = skb->data + ring->desc_size;
- desc->ring = ring;
- desc->entry = beacon;
-
+ control->queue = RT2X00_BCN_QUEUE_BEACON;
rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
/*
*/
length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
- usb_fill_bulk_urb(beacon->priv, usb_dev, pipe,
- skb->data, length, rt2500usb_beacondone, beacon);
+ usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe,
+ skb->data, length, rt2500usb_beacondone,
+ intf->beacon);
/*
* Second we need to create the guardian byte.
* We only need a single byte, so lets recycle
* the 'flags' field we are not using for beacons.
*/
- guardian->flags = 0;
- usb_fill_bulk_urb(guardian->priv, usb_dev, pipe,
- &guardian->flags, 1, rt2500usb_beacondone, guardian);
+ priv_bcn->guardian_data = 0;
+ usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe,
+ &priv_bcn->guardian_data, 1, rt2500usb_beacondone,
+ intf->beacon);
/*
* Send out the guardian byte.
*/
- usb_submit_urb(guardian->priv, GFP_ATOMIC);
+ usb_submit_urb(priv_bcn->guardian_urb, GFP_ATOMIC);
/*
* Enable beacon generation.
*/
- rt2500usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ rt2500usb_kick_tx_queue(rt2x00dev, control->queue);
return 0;
}
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
.link_tuner = rt2500usb_link_tuner,
+ .led_brightness = rt2500usb_led_brightness,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
.get_tx_data_len = rt2500usb_get_tx_data_len,
.kick_tx_queue = rt2500usb_kick_tx_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
- .config_mac_addr = rt2500usb_config_mac_addr,
- .config_bssid = rt2500usb_config_bssid,
- .config_type = rt2500usb_config_type,
- .config_preamble = rt2500usb_config_preamble,
+ .config_intf = rt2500usb_config_intf,
+ .config_erp = rt2500usb_config_erp,
.config = rt2500usb_config,
};
+static const struct data_queue_desc rt2500usb_queue_rx = {
+ .entry_num = RX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = RXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_usb_rx),
+};
+
+static const struct data_queue_desc rt2500usb_queue_tx = {
+ .entry_num = TX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_usb_tx),
+};
+
+static const struct data_queue_desc rt2500usb_queue_bcn = {
+ .entry_num = BEACON_ENTRIES,
+ .data_size = MGMT_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_usb_bcn),
+};
+
+static const struct data_queue_desc rt2500usb_queue_atim = {
+ .entry_num = ATIM_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_usb_tx),
+};
+
static const struct rt2x00_ops rt2500usb_ops = {
.name = KBUILD_MODNAME,
- .rxd_size = RXD_DESC_SIZE,
- .txd_size = TXD_DESC_SIZE,
+ .max_sta_intf = 1,
+ .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .rx = &rt2500usb_queue_rx,
+ .tx = &rt2500usb_queue_tx,
+ .bcn = &rt2500usb_queue_bcn,
+ .atim = &rt2500usb_queue_atim,
.lib = &rt2500usb_rt2x00_ops,
.hw = &rt2500usb_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
* Misc MAC_CSR registers.
* MAC_CSR9: Timer control.
* MAC_CSR10: Slot time.
- * MAC_CSR11: IFS.
+ * MAC_CSR11: SIFS.
* MAC_CSR12: EIFS.
* MAC_CSR13: Power mode0.
* MAC_CSR14: Power mode1.
*/
#define EEPROM_BBPTUNE_VGC 0x0034
#define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_VGCLOWER FIELD16(0xff00)
/*
* EEPROM BBP R17 Tuning.
#define RXD_W3_EIV FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to dscape value
- * and from dscape value to register value.
+ * Macro's for converting txpower from EEPROM to mac80211 value
+ * and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
#define MAX_TXPOWER 31
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#define RT2X00_H
#include <linux/bitops.h>
-#include <linux/prefetch.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
+#include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/etherdevice.h>
#include <net/mac80211.h>
#include "rt2x00debug.h"
+#include "rt2x00leds.h"
#include "rt2x00reg.h"
-#include "rt2x00ring.h"
+#include "rt2x00queue.h"
/*
* Module information.
*/
-#define DRV_VERSION "2.0.14"
+#define DRV_VERSION "2.1.4"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
/*
DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args)
/*
- * Ring sizes.
- * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes.
- * DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings.
- * MGMT_FRAME_SIZE is used for the BEACON ring.
- */
-#define DATA_FRAME_SIZE 2432
-#define MGMT_FRAME_SIZE 256
-
-/*
- * Number of entries in a packet ring.
- * PCI devices only need 1 Beacon entry,
- * but USB devices require a second because they
- * have to send a Guardian byte first.
- */
-#define RX_ENTRIES 12
-#define TX_ENTRIES 12
-#define ATIM_ENTRIES 1
-#define BEACON_ENTRIES 2
-
-/*
* Standard timing and size defines.
* These values should follow the ieee80211 specifications.
*/
/*
* Interface structure
- * Configuration details about the current interface.
+ * Per interface configuration details, this structure
+ * is allocated as the private data for ieee80211_vif.
*/
-struct interface {
+struct rt2x00_intf {
/*
- * Interface identification. The value is assigned
- * to us by the 80211 stack, and is used to request
- * new beacons.
+ * All fields within the rt2x00_intf structure
+ * must be protected with a spinlock.
*/
- struct ieee80211_vif *id;
+ spinlock_t lock;
/*
- * Current working type (IEEE80211_IF_TYPE_*).
+ * BSS configuration. Copied from the structure
+ * passed to us through the bss_info_changed()
+ * callback funtion.
*/
- int type;
+ struct ieee80211_bss_conf conf;
/*
* MAC of the device.
* BBSID of the AP to associate with.
*/
u8 bssid[ETH_ALEN];
-};
-static inline int is_interface_present(struct interface *intf)
-{
- return !!intf->id;
-}
+ /*
+ * Entry in the beacon queue which belongs to
+ * this interface. Each interface has its own
+ * dedicated beacon entry.
+ */
+ struct queue_entry *beacon;
+
+ /*
+ * Actions that needed rescheduling.
+ */
+ unsigned int delayed_flags;
+#define DELAYED_UPDATE_BEACON 0x00000001
+#define DELAYED_CONFIG_ERP 0x00000002
+};
-static inline int is_interface_type(struct interface *intf, int type)
+static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
{
- return intf->type == type;
+ return (struct rt2x00_intf *)vif->drv_priv;
}
-/*
+/**
+ * struct hw_mode_spec: Hardware specifications structure
+ *
* Details about the supported modes, rates and channels
* of a particular chipset. This is used by rt2x00lib
* to build the ieee80211_hw_mode array for mac80211.
+ *
+ * @supported_bands: Bitmask contained the supported bands (2.4GHz, 5.2GHz).
+ * @supported_rates: Rate types which are supported (CCK, OFDM).
+ * @num_channels: Number of supported channels. This is used as array size
+ * for @tx_power_a, @tx_power_bg and @channels.
+ * channels: Device/chipset specific channel values (See &struct rf_channel).
+ * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL).
+ * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL).
+ * @tx_power_default: Default TX power value to use when either
+ * @tx_power_a or @tx_power_bg is missing.
*/
struct hw_mode_spec {
- /*
- * Number of modes, rates and channels.
- */
- int num_modes;
- int num_rates;
- int num_channels;
+ unsigned int supported_bands;
+#define SUPPORT_BAND_2GHZ 0x00000001
+#define SUPPORT_BAND_5GHZ 0x00000002
+
+ unsigned int supported_rates;
+#define SUPPORT_RATE_CCK 0x00000001
+#define SUPPORT_RATE_OFDM 0x00000002
+
+ unsigned int num_channels;
+ const struct rf_channel *channels;
- /*
- * txpower values.
- */
const u8 *tx_power_a;
const u8 *tx_power_bg;
u8 tx_power_default;
-
- /*
- * Device/chipset specific value.
- */
- const struct rf_channel *channels;
};
/*
struct antenna_setup ant;
- int phymode;
+ enum ieee80211_band band;
- int basic_rates;
- int slot_time;
+ u32 basic_rates;
+ u32 slot_time;
short sifs;
short pifs;
};
/*
+ * Configuration structure for erp settings.
+ */
+struct rt2x00lib_erp {
+ int short_preamble;
+
+ int ack_timeout;
+ int ack_consume_time;
+};
+
+/*
+ * Configuration structure wrapper around the
+ * rt2x00 interface configuration handler.
+ */
+struct rt2x00intf_conf {
+ /*
+ * Interface type
+ */
+ enum ieee80211_if_types type;
+
+ /*
+ * TSF sync value, this is dependant on the operation type.
+ */
+ enum tsf_sync sync;
+
+ /*
+ * The MAC and BSSID addressess are simple array of bytes,
+ * these arrays are little endian, so when sending the addressess
+ * to the drivers, copy the it into a endian-signed variable.
+ *
+ * Note that all devices (except rt2500usb) have 32 bits
+ * register word sizes. This means that whatever variable we
+ * pass _must_ be a multiple of 32 bits. Otherwise the device
+ * might not accept what we are sending to it.
+ * This will also make it easier for the driver to write
+ * the data to the device.
+ */
+ __le32 mac[2];
+ __le32 bssid[2];
+};
+
+/*
* rt2x00lib callback functions.
*/
struct rt2x00lib_ops {
*/
int (*probe_hw) (struct rt2x00_dev *rt2x00dev);
char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev);
+ u16 (*get_firmware_crc) (void *data, const size_t len);
int (*load_firmware) (struct rt2x00_dev *rt2x00dev, void *data,
const size_t len);
void (*uninitialize) (struct rt2x00_dev *rt2x00dev);
/*
- * Ring initialization handlers
+ * queue initialization handlers
*/
void (*init_rxentry) (struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry);
+ struct queue_entry *entry);
void (*init_txentry) (struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry);
+ struct queue_entry *entry);
/*
* Radio control handlers.
struct link_qual *qual);
void (*reset_tuner) (struct rt2x00_dev *rt2x00dev);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev);
+ void (*led_brightness) (struct led_classdev *led_cdev,
+ enum led_brightness brightness);
/*
* TX control handlers
*/
void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txdata_entry_desc *desc,
+ struct txentry_desc *txdesc,
struct ieee80211_tx_control *control);
int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring, struct sk_buff *skb,
+ struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_tx_control *control);
int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb);
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
- unsigned int queue);
+ const unsigned int queue);
/*
* RX control handlers
*/
- void (*fill_rxdone) (struct data_entry *entry,
- struct rxdata_entry_desc *desc);
+ void (*fill_rxdone) (struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc);
/*
* Configuration handlers.
*/
- void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac);
- void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid);
- void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type,
- const int tsf_sync);
- void (*config_preamble) (struct rt2x00_dev *rt2x00dev,
- const int short_preamble,
- const int ack_timeout,
- const int ack_consume_time);
- void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags,
- struct rt2x00lib_conf *libconf);
+ void (*config_intf) (struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct rt2x00intf_conf *conf,
+ const unsigned int flags);
+#define CONFIG_UPDATE_TYPE ( 1 << 1 )
+#define CONFIG_UPDATE_MAC ( 1 << 2 )
+#define CONFIG_UPDATE_BSSID ( 1 << 3 )
+
+ int (*config_erp) (struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp);
+ void (*config) (struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf,
+ const unsigned int flags);
#define CONFIG_UPDATE_PHYMODE ( 1 << 1 )
#define CONFIG_UPDATE_CHANNEL ( 1 << 2 )
#define CONFIG_UPDATE_TXPOWER ( 1 << 3 )
*/
struct rt2x00_ops {
const char *name;
- const unsigned int rxd_size;
- const unsigned int txd_size;
+ const unsigned int max_sta_intf;
+ const unsigned int max_ap_intf;
const unsigned int eeprom_size;
const unsigned int rf_size;
+ const struct data_queue_desc *rx;
+ const struct data_queue_desc *tx;
+ const struct data_queue_desc *bcn;
+ const struct data_queue_desc *atim;
const struct rt2x00lib_ops *lib;
const struct ieee80211_ops *hw;
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
/*
* Driver features
*/
+ DRIVER_SUPPORT_MIXED_INTERFACES,
DRIVER_REQUIRE_FIRMWARE,
- DRIVER_REQUIRE_BEACON_RING,
+ DRIVER_REQUIRE_BEACON_GUARD,
+ DRIVER_REQUIRE_ATIM_QUEUE,
/*
* Driver configuration
CONFIG_EXTERNAL_LNA_BG,
CONFIG_DOUBLE_ANTENNA,
CONFIG_DISABLE_LINK_TUNING,
- CONFIG_SHORT_PREAMBLE,
};
/*
* macro's should be used for correct typecasting.
*/
void *dev;
-#define rt2x00dev_pci(__dev) ( (struct pci_dev*)(__dev)->dev )
-#define rt2x00dev_usb(__dev) ( (struct usb_interface*)(__dev)->dev )
+#define rt2x00dev_pci(__dev) ( (struct pci_dev *)(__dev)->dev )
+#define rt2x00dev_usb(__dev) ( (struct usb_interface *)(__dev)->dev )
+#define rt2x00dev_usb_dev(__dev)\
+ ( (struct usb_device *)interface_to_usbdev(rt2x00dev_usb(__dev)) )
/*
* Callback functions.
* IEEE80211 control structure.
*/
struct ieee80211_hw *hw;
- struct ieee80211_hw_mode *hwmodes;
- unsigned int curr_hwmode;
-#define HWMODE_B 0
-#define HWMODE_G 1
-#define HWMODE_A 2
+ struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
+ enum ieee80211_band curr_band;
/*
* rfkill structure for RF state switching support.
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
/*
+ * LED structure for changing the LED status
+ * by mac8011 or the kernel.
+ */
+#ifdef CONFIG_RT2X00_LIB_LEDS
+ unsigned int led_flags;
+ struct rt2x00_trigger trigger_qual;
+ struct rt2x00_led led_radio;
+ struct rt2x00_led led_assoc;
+ struct rt2x00_led led_qual;
+ u16 led_mcu_reg;
+#endif /* CONFIG_RT2X00_LIB_LEDS */
+
+ /*
* Device flags.
* In these flags the current status and some
* of the device capabilities are stored.
/*
* Register pointers
- * csr_addr: Base register address. (PCI)
- * csr_cache: CSR cache for usb_control_msg. (USB)
+ * csr.base: CSR base register address. (PCI)
+ * csr.cache: CSR cache for usb_control_msg. (USB)
*/
- void __iomem *csr_addr;
- void *csr_cache;
+ union csr {
+ void __iomem *base;
+ void *cache;
+ } csr;
/*
* Mutex to protect register accesses on USB devices.
unsigned int packet_filter;
/*
- * Interface configuration.
+ * Interface details:
+ * - Open ap interface count.
+ * - Open sta interface count.
+ * - Association count.
*/
- struct interface interface;
+ unsigned int intf_ap_count;
+ unsigned int intf_sta_count;
+ unsigned int intf_associated;
/*
* Link quality
u16 tx_power;
/*
- * LED register (for rt61pci & rt73usb).
- */
- u16 led_reg;
-
- /*
- * Led mode (LED_MODE_*)
- */
- u8 led_mode;
-
- /*
* Rssi <-> Dbm offset
*/
u8 rssi_offset;
/*
* Scheduled work.
*/
- struct work_struct beacon_work;
+ struct work_struct intf_work;
struct work_struct filter_work;
- struct work_struct config_work;
/*
- * Data ring arrays for RX, TX and Beacon.
- * The Beacon array also contains the Atim ring
+ * Data queue arrays for RX, TX and Beacon.
+ * The Beacon array also contains the Atim queue
* if that is supported by the device.
*/
- int data_rings;
- struct data_ring *rx;
- struct data_ring *tx;
- struct data_ring *bcn;
+ int data_queues;
+ struct data_queue *rx;
+ struct data_queue *tx;
+ struct data_queue *bcn;
/*
* Firmware image.
};
/*
- * For-each loop for the ring array.
- * All rings have been allocated as a single array,
- * this means we can create a very simply loop macro
- * that is capable of looping through all rings.
- * ring_end(), txring_end() and ring_loop() are helper macro's which
- * should not be used directly. Instead the following should be used:
- * ring_for_each() - Loops through all rings (RX, TX, Beacon & Atim)
- * txring_for_each() - Loops through TX data rings (TX only)
- * txringall_for_each() - Loops through all TX rings (TX, Beacon & Atim)
- */
-#define ring_end(__dev) \
- &(__dev)->rx[(__dev)->data_rings]
-
-#define txring_end(__dev) \
- &(__dev)->tx[(__dev)->hw->queues]
-
-#define ring_loop(__entry, __start, __end) \
- for ((__entry) = (__start); \
- prefetch(&(__entry)[1]), (__entry) != (__end); \
- (__entry) = &(__entry)[1])
-
-#define ring_for_each(__dev, __entry) \
- ring_loop(__entry, (__dev)->rx, ring_end(__dev))
-
-#define txring_for_each(__dev, __entry) \
- ring_loop(__entry, (__dev)->tx, txring_end(__dev))
-
-#define txringall_for_each(__dev, __entry) \
- ring_loop(__entry, (__dev)->tx, ring_end(__dev))
-
-/*
* Generic RF access.
* The RF is being accessed by word index.
*/
return ((size * 8 * 10) % rate);
}
-/*
- * Library functions.
+/**
+ * rt2x00queue_get_queue - Convert mac80211 queue index to rt2x00 queue
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @queue: mac80211/rt2x00 queue index
+ * (see &enum ieee80211_tx_queue and &enum rt2x00_bcn_queue).
+ */
+struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
+ const unsigned int queue);
+
+/**
+ * rt2x00queue_get_entry - Get queue entry where the given index points to.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @index: Index identifier for obtaining the correct index.
+ */
+struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
+ enum queue_index index);
+
+/**
+ * rt2x00queue_index_inc - Index incrementation function
+ * @queue: Queue (&struct data_queue) to perform the action on.
+ * @action: Index type (&enum queue_index) to perform the action on.
+ *
+ * This function will increase the requested index on the queue,
+ * it will grab the appropriate locks and handle queue overflow events by
+ * resetting the index to the start of the queue.
*/
-struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
- const unsigned int queue);
+void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
+
/*
* Interrupt context handlers.
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
-void rt2x00lib_txdone(struct data_entry *entry,
- const int status, const int retry);
-void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
- struct rxdata_entry_desc *desc);
+void rt2x00lib_txdone(struct queue_entry *entry,
+ struct txdone_entry_desc *txdesc);
+void rt2x00lib_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc);
/*
* TX descriptor initializer
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#include "rt2x00.h"
#include "rt2x00lib.h"
-
-/*
- * The MAC and BSSID addressess are simple array of bytes,
- * these arrays are little endian, so when sending the addressess
- * to the drivers, copy the it into a endian-signed variable.
- *
- * Note that all devices (except rt2500usb) have 32 bits
- * register word sizes. This means that whatever variable we
- * pass _must_ be a multiple of 32 bits. Otherwise the device
- * might not accept what we are sending to it.
- * This will also make it easier for the driver to write
- * the data to the device.
- *
- * Also note that when NULL is passed as address the
- * we will send 00:00:00:00:00 to the device to clear the address.
- * This will prevent the device being confused when it wants
- * to ACK frames or consideres itself associated.
- */
-void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac)
+void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ enum ieee80211_if_types type,
+ u8 *mac, u8 *bssid)
{
- __le32 reg[2];
+ struct rt2x00intf_conf conf;
+ unsigned int flags = 0;
- memset(®, 0, sizeof(reg));
- if (mac)
- memcpy(®, mac, ETH_ALEN);
-
- rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, ®[0]);
-}
-
-void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid)
-{
- __le32 reg[2];
-
- memset(®, 0, sizeof(reg));
- if (bssid)
- memcpy(®, bssid, ETH_ALEN);
-
- rt2x00dev->ops->lib->config_bssid(rt2x00dev, ®[0]);
-}
-
-void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type)
-{
- int tsf_sync;
+ conf.type = type;
switch (type) {
case IEEE80211_IF_TYPE_IBSS:
case IEEE80211_IF_TYPE_AP:
- tsf_sync = TSF_SYNC_BEACON;
+ conf.sync = TSF_SYNC_BEACON;
break;
case IEEE80211_IF_TYPE_STA:
- tsf_sync = TSF_SYNC_INFRA;
+ conf.sync = TSF_SYNC_INFRA;
break;
default:
- tsf_sync = TSF_SYNC_NONE;
+ conf.sync = TSF_SYNC_NONE;
break;
}
- rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync);
+ /*
+ * Note that when NULL is passed as address we will send
+ * 00:00:00:00:00 to the device to clear the address.
+ * This will prevent the device being confused when it wants
+ * to ACK frames or consideres itself associated.
+ */
+ memset(&conf.mac, 0, sizeof(conf.mac));
+ if (mac)
+ memcpy(&conf.mac, mac, ETH_ALEN);
+
+ memset(&conf.bssid, 0, sizeof(conf.bssid));
+ if (bssid)
+ memcpy(&conf.bssid, bssid, ETH_ALEN);
+
+ flags |= CONFIG_UPDATE_TYPE;
+ if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
+ flags |= CONFIG_UPDATE_MAC;
+ if (bssid || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
+ flags |= CONFIG_UPDATE_BSSID;
+
+ rt2x00dev->ops->lib->config_intf(rt2x00dev, intf, &conf, flags);
+}
+
+void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct ieee80211_bss_conf *bss_conf)
+{
+ struct rt2x00lib_erp erp;
+ int retval;
+
+ memset(&erp, 0, sizeof(erp));
+
+ erp.short_preamble = bss_conf->use_short_preamble;
+ erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10);
+ erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
+
+ if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME)
+ erp.ack_timeout += SHORT_DIFS;
+ else
+ erp.ack_timeout += DIFS;
+
+ if (bss_conf->use_short_preamble) {
+ erp.ack_timeout += SHORT_PREAMBLE;
+ erp.ack_consume_time += SHORT_PREAMBLE;
+ } else {
+ erp.ack_timeout += PREAMBLE;
+ erp.ack_consume_time += PREAMBLE;
+ }
+
+ retval = rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
+
+ if (retval) {
+ spin_lock(&intf->lock);
+ intf->delayed_flags |= DELAYED_CONFIG_ERP;
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+ spin_unlock(&intf->lock);
+ }
}
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* The latter is required since we need to recalibrate the
* noise-sensitivity ratio for the new setup.
*/
- rt2x00dev->ops->lib->config(rt2x00dev, CONFIG_UPDATE_ANTENNA, &libconf);
+ rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA);
rt2x00lib_reset_link_tuner(rt2x00dev);
rt2x00dev->link.ant.active.rx = libconf.ant.rx;
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
}
+static u32 rt2x00lib_get_basic_rates(struct ieee80211_supported_band *band)
+{
+ const struct rt2x00_rate *rate;
+ unsigned int i;
+ u32 mask = 0;
+
+ for (i = 0; i < band->n_bitrates; i++) {
+ rate = rt2x00_get_rate(band->bitrates[i].hw_value);
+ if (rate->flags & DEV_RATE_BASIC)
+ mask |= rate->ratemask;
+ }
+
+ return mask;
+}
+
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf, const int force_config)
{
struct rt2x00lib_conf libconf;
- struct ieee80211_hw_mode *mode;
- struct ieee80211_rate *rate;
+ struct ieee80211_supported_band *band;
struct antenna_setup *default_ant = &rt2x00dev->default_ant;
struct antenna_setup *active_ant = &rt2x00dev->link.ant.active;
int flags = 0;
* Check which configuration options have been
* updated and should be send to the device.
*/
- if (rt2x00dev->rx_status.phymode != conf->phymode)
+ if (rt2x00dev->rx_status.band != conf->channel->band)
flags |= CONFIG_UPDATE_PHYMODE;
- if (rt2x00dev->rx_status.channel != conf->channel)
+ if (rt2x00dev->rx_status.freq != conf->channel->center_freq)
flags |= CONFIG_UPDATE_CHANNEL;
if (rt2x00dev->tx_power != conf->power_level)
flags |= CONFIG_UPDATE_TXPOWER;
memset(&libconf, 0, sizeof(libconf));
if (flags & CONFIG_UPDATE_PHYMODE) {
- switch (conf->phymode) {
- case MODE_IEEE80211A:
- libconf.phymode = HWMODE_A;
- break;
- case MODE_IEEE80211B:
- libconf.phymode = HWMODE_B;
- break;
- case MODE_IEEE80211G:
- libconf.phymode = HWMODE_G;
- break;
- default:
- ERROR(rt2x00dev,
- "Attempt to configure unsupported mode (%d)"
- "Defaulting to 802.11b", conf->phymode);
- libconf.phymode = HWMODE_B;
- }
-
- mode = &rt2x00dev->hwmodes[libconf.phymode];
- rate = &mode->rates[mode->num_rates - 1];
-
- libconf.basic_rates =
- DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK;
+ band = &rt2x00dev->bands[conf->channel->band];
+
+ libconf.band = conf->channel->band;
+ libconf.basic_rates = rt2x00lib_get_basic_rates(band);
}
if (flags & CONFIG_UPDATE_CHANNEL) {
memcpy(&libconf.rf,
- &rt2x00dev->spec.channels[conf->channel_val],
+ &rt2x00dev->spec.channels[conf->channel->hw_value],
sizeof(libconf.rf));
}
/*
* Start configuration.
*/
- rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf);
+ rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags);
/*
* Some configuration changes affect the link quality
rt2x00lib_reset_link_tuner(rt2x00dev);
if (flags & CONFIG_UPDATE_PHYMODE) {
- rt2x00dev->curr_hwmode = libconf.phymode;
- rt2x00dev->rx_status.phymode = conf->phymode;
+ rt2x00dev->curr_band = conf->channel->band;
+ rt2x00dev->rx_status.band = conf->channel->band;
}
- rt2x00dev->rx_status.freq = conf->freq;
- rt2x00dev->rx_status.channel = conf->channel;
+ rt2x00dev->rx_status.freq = conf->channel->center_freq;
rt2x00dev->tx_power = conf->power_level;
if (flags & CONFIG_UPDATE_ANTENNA) {
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#include "rt2x00lib.h"
#include "rt2x00dump.h"
-#define PRINT_LINE_LEN_MAX 32
+#define MAX_LINE_LENGTH 64
struct rt2x00debug_intf {
/*
* - eeprom offset/value files
* - bbp offset/value files
* - rf offset/value files
- * - frame dump folder
+ * - queue folder
* - frame dump file
+ * - queue stats file
*/
struct dentry *driver_folder;
struct dentry *driver_entry;
struct dentry *bbp_val_entry;
struct dentry *rf_off_entry;
struct dentry *rf_val_entry;
- struct dentry *frame_folder;
- struct dentry *frame_dump_entry;
+ struct dentry *queue_folder;
+ struct dentry *queue_frame_dump_entry;
+ struct dentry *queue_stats_entry;
/*
* The frame dump file only allows a single reader,
struct sk_buff *skb)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
- struct skb_desc *desc = get_skb_desc(skb);
+ struct skb_frame_desc *desc = get_skb_frame_desc(skb);
struct sk_buff *skbcopy;
struct rt2x00dump_hdr *dump_hdr;
struct timeval timestamp;
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
dump_hdr->type = cpu_to_le16(desc->frame_type);
- dump_hdr->ring_index = desc->ring->queue_idx;
+ dump_hdr->queue_index = desc->entry->queue->qid;
dump_hdr->entry_index = desc->entry->entry_idx;
dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
return 0;
}
-static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file)
+static int rt2x00debug_open_queue_dump(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
int retval;
return 0;
}
-static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file)
+static int rt2x00debug_release_queue_dump(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
return rt2x00debug_file_release(inode, file);
}
-static ssize_t rt2x00debug_read_ring_dump(struct file *file,
- char __user *buf,
- size_t length,
- loff_t *offset)
+static ssize_t rt2x00debug_read_queue_dump(struct file *file,
+ char __user *buf,
+ size_t length,
+ loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
struct sk_buff *skb;
return status;
}
-static unsigned int rt2x00debug_poll_ring_dump(struct file *file,
- poll_table *wait)
+static unsigned int rt2x00debug_poll_queue_dump(struct file *file,
+ poll_table *wait)
{
struct rt2x00debug_intf *intf = file->private_data;
return 0;
}
-static const struct file_operations rt2x00debug_fop_ring_dump = {
+static const struct file_operations rt2x00debug_fop_queue_dump = {
.owner = THIS_MODULE,
- .read = rt2x00debug_read_ring_dump,
- .poll = rt2x00debug_poll_ring_dump,
- .open = rt2x00debug_open_ring_dump,
- .release = rt2x00debug_release_ring_dump,
+ .read = rt2x00debug_read_queue_dump,
+ .poll = rt2x00debug_poll_queue_dump,
+ .open = rt2x00debug_open_queue_dump,
+ .release = rt2x00debug_release_queue_dump,
+};
+
+static ssize_t rt2x00debug_read_queue_stats(struct file *file,
+ char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+ struct data_queue *queue;
+ unsigned long irqflags;
+ unsigned int lines = 1 + intf->rt2x00dev->data_queues;
+ size_t size;
+ char *data;
+ char *temp;
+
+ if (*offset)
+ return 0;
+
+ data = kzalloc(lines * MAX_LINE_LENGTH, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ temp = data +
+ sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n");
+
+ queue_for_each(intf->rt2x00dev, queue) {
+ spin_lock_irqsave(&queue->lock, irqflags);
+
+ temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
+ queue->count, queue->limit, queue->length,
+ queue->index[Q_INDEX],
+ queue->index[Q_INDEX_DONE],
+ queue->index[Q_INDEX_CRYPTO]);
+
+ spin_unlock_irqrestore(&queue->lock, irqflags);
+ }
+
+ size = strlen(data);
+ size = min(size, length);
+
+ if (copy_to_user(buf, data, size)) {
+ kfree(data);
+ return -EFAULT;
+ }
+
+ kfree(data);
+
+ *offset += size;
+ return size;
+}
+
+static const struct file_operations rt2x00debug_fop_queue_stats = {
+ .owner = THIS_MODULE,
+ .read = rt2x00debug_read_queue_stats,
+ .open = rt2x00debug_file_open,
+ .release = rt2x00debug_file_release,
};
#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
{
char *data;
- data = kzalloc(3 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+ data = kzalloc(3 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return NULL;
const struct rt2x00debug *debug = intf->debug;
char *data;
- data = kzalloc(8 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+ data = kzalloc(8 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return NULL;
#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
- intf->frame_folder =
- debugfs_create_dir("frame", intf->driver_folder);
- if (IS_ERR(intf->frame_folder))
+ intf->queue_folder =
+ debugfs_create_dir("queue", intf->driver_folder);
+ if (IS_ERR(intf->queue_folder))
goto exit;
- intf->frame_dump_entry =
- debugfs_create_file("dump", S_IRUGO, intf->frame_folder,
- intf, &rt2x00debug_fop_ring_dump);
- if (IS_ERR(intf->frame_dump_entry))
+ intf->queue_frame_dump_entry =
+ debugfs_create_file("dump", S_IRUGO, intf->queue_folder,
+ intf, &rt2x00debug_fop_queue_dump);
+ if (IS_ERR(intf->queue_frame_dump_entry))
goto exit;
skb_queue_head_init(&intf->frame_dump_skbqueue);
init_waitqueue_head(&intf->frame_dump_waitqueue);
+ intf->queue_stats_entry =
+ debugfs_create_file("queue", S_IRUGO, intf->queue_folder,
+ intf, &rt2x00debug_fop_queue_stats);
+
return;
exit:
skb_queue_purge(&intf->frame_dump_skbqueue);
- debugfs_remove(intf->frame_dump_entry);
- debugfs_remove(intf->frame_folder);
+ debugfs_remove(intf->queue_stats_entry);
+ debugfs_remove(intf->queue_frame_dump_entry);
+ debugfs_remove(intf->queue_folder);
debugfs_remove(intf->rf_val_entry);
debugfs_remove(intf->rf_off_entry);
debugfs_remove(intf->bbp_val_entry);
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#include "rt2x00dump.h"
/*
- * Ring handler.
- */
-struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
- const unsigned int queue)
-{
- int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
-
- /*
- * Check if we are requesting a reqular TX ring,
- * or if we are requesting a Beacon or Atim ring.
- * For Atim rings, we should check if it is supported.
- */
- if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
- return &rt2x00dev->tx[queue];
-
- if (!rt2x00dev->bcn || !beacon)
- return NULL;
-
- if (queue == IEEE80211_TX_QUEUE_BEACON)
- return &rt2x00dev->bcn[0];
- else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
- return &rt2x00dev->bcn[1];
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(rt2x00lib_get_ring);
-
-/*
* Link tuning handlers
*/
void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
}
/*
- * Ring initialization
- */
-static void rt2x00lib_init_rxrings(struct rt2x00_dev *rt2x00dev)
-{
- struct data_ring *ring = rt2x00dev->rx;
- unsigned int i;
-
- if (!rt2x00dev->ops->lib->init_rxentry)
- return;
-
- if (ring->data_addr)
- memset(ring->data_addr, 0, rt2x00_get_ring_size(ring));
-
- for (i = 0; i < ring->stats.limit; i++)
- rt2x00dev->ops->lib->init_rxentry(rt2x00dev, &ring->entry[i]);
-
- rt2x00_ring_index_clear(ring);
-}
-
-static void rt2x00lib_init_txrings(struct rt2x00_dev *rt2x00dev)
-{
- struct data_ring *ring;
- unsigned int i;
-
- if (!rt2x00dev->ops->lib->init_txentry)
- return;
-
- txringall_for_each(rt2x00dev, ring) {
- if (ring->data_addr)
- memset(ring->data_addr, 0, rt2x00_get_ring_size(ring));
-
- for (i = 0; i < ring->stats.limit; i++)
- rt2x00dev->ops->lib->init_txentry(rt2x00dev,
- &ring->entry[i]);
-
- rt2x00_ring_index_clear(ring);
- }
-}
-
-/*
* Radio control handlers.
*/
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
return 0;
/*
- * Initialize all data rings.
+ * Initialize all data queues.
*/
- rt2x00lib_init_rxrings(rt2x00dev);
- rt2x00lib_init_txrings(rt2x00dev);
+ rt2x00queue_init_rx(rt2x00dev);
+ rt2x00queue_init_tx(rt2x00dev);
/*
* Enable radio.
/*
* Stop all scheduled work.
*/
- if (work_pending(&rt2x00dev->beacon_work))
- cancel_work_sync(&rt2x00dev->beacon_work);
+ if (work_pending(&rt2x00dev->intf_work))
+ cancel_work_sync(&rt2x00dev->intf_work);
if (work_pending(&rt2x00dev->filter_work))
cancel_work_sync(&rt2x00dev->filter_work);
- if (work_pending(&rt2x00dev->config_work))
- cancel_work_sync(&rt2x00dev->config_work);
/*
* Stop the TX queues.
* When we are enabling the RX, we should also start the link tuner.
*/
if (state == STATE_RADIO_RX_ON &&
- is_interface_present(&rt2x00dev->interface))
+ (rt2x00dev->intf_ap_count || rt2x00dev->intf_sta_count))
rt2x00lib_start_link_tuner(rt2x00dev);
}
rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual);
/*
+ * Send a signal to the led to update the led signal strength.
+ */
+ rt2x00leds_led_quality(rt2x00dev, rt2x00dev->link.qual.avg_rssi);
+
+ /*
* Evaluate antenna setup, make this the last step since this could
* possibly reset some statistics.
*/
unsigned int filter = rt2x00dev->packet_filter;
/*
- * Since we had stored the filter inside interface.filter,
+ * Since we had stored the filter inside rt2x00dev->packet_filter,
* we should now clear that field. Otherwise the driver will
* assume nothing has changed (*total_flags will be compared
- * to interface.filter to determine if any action is required).
+ * to rt2x00dev->packet_filter to determine if any action is required).
*/
rt2x00dev->packet_filter = 0;
filter, &filter, 0, NULL);
}
-static void rt2x00lib_configuration_scheduled(struct work_struct *work)
+static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
{
- struct rt2x00_dev *rt2x00dev =
- container_of(work, struct rt2x00_dev, config_work);
- struct ieee80211_bss_conf bss_conf;
+ struct rt2x00_dev *rt2x00dev = data;
+ struct rt2x00_intf *intf = vif_to_intf(vif);
+ struct sk_buff *skb;
+ struct ieee80211_tx_control control;
+ struct ieee80211_bss_conf conf;
+ int delayed_flags;
+
+ /*
+ * Copy all data we need during this action under the protection
+ * of a spinlock. Otherwise race conditions might occur which results
+ * into an invalid configuration.
+ */
+ spin_lock(&intf->lock);
+
+ memcpy(&conf, &intf->conf, sizeof(conf));
+ delayed_flags = intf->delayed_flags;
+ intf->delayed_flags = 0;
+
+ spin_unlock(&intf->lock);
- bss_conf.use_short_preamble =
- test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+ if (delayed_flags & DELAYED_UPDATE_BEACON) {
+ skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control);
+ if (skb) {
+ rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb,
+ &control);
+ dev_kfree_skb(skb);
+ }
+ }
+
+ if (delayed_flags & DELAYED_CONFIG_ERP)
+ rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf);
+}
+
+static void rt2x00lib_intf_scheduled(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, intf_work);
/*
- * FIXME: shouldn't invoke it this way because all other contents
- * of bss_conf is invalid.
+ * Iterate over each interface and perform the
+ * requested configurations.
*/
- rt2x00mac_bss_info_changed(rt2x00dev->hw, rt2x00dev->interface.id,
- &bss_conf, BSS_CHANGED_ERP_PREAMBLE);
+ ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+ rt2x00lib_intf_scheduled_iter,
+ rt2x00dev);
}
/*
* Interrupt context handlers.
*/
-static void rt2x00lib_beacondone_scheduled(struct work_struct *work)
+static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
{
- struct rt2x00_dev *rt2x00dev =
- container_of(work, struct rt2x00_dev, beacon_work);
- struct data_ring *ring =
- rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
- struct data_entry *entry = rt2x00_get_data_entry(ring);
- struct sk_buff *skb;
+ struct rt2x00_intf *intf = vif_to_intf(vif);
- skb = ieee80211_beacon_get(rt2x00dev->hw,
- rt2x00dev->interface.id,
- &entry->tx_status.control);
- if (!skb)
+ if (vif->type != IEEE80211_IF_TYPE_AP &&
+ vif->type != IEEE80211_IF_TYPE_IBSS)
return;
- rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb,
- &entry->tx_status.control);
-
- dev_kfree_skb(skb);
+ spin_lock(&intf->lock);
+ intf->delayed_flags |= DELAYED_UPDATE_BEACON;
+ spin_unlock(&intf->lock);
}
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work);
+ ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+ rt2x00lib_beacondone_iter,
+ rt2x00dev);
+
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
-void rt2x00lib_txdone(struct data_entry *entry,
- const int status, const int retry)
+void rt2x00lib_txdone(struct queue_entry *entry,
+ struct txdone_entry_desc *txdesc)
{
- struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
- struct ieee80211_tx_status *tx_status = &entry->tx_status;
- struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats;
- int success = !!(status == TX_SUCCESS || status == TX_SUCCESS_RETRY);
- int fail = !!(status == TX_FAIL_RETRY || status == TX_FAIL_INVALID ||
- status == TX_FAIL_OTHER);
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc;
+ struct ieee80211_tx_status tx_status;
+ int success = !!(txdesc->status == TX_SUCCESS ||
+ txdesc->status == TX_SUCCESS_RETRY);
+ int fail = !!(txdesc->status == TX_FAIL_RETRY ||
+ txdesc->status == TX_FAIL_INVALID ||
+ txdesc->status == TX_FAIL_OTHER);
/*
* Update TX statistics.
*/
- tx_status->flags = 0;
- tx_status->ack_signal = 0;
- tx_status->excessive_retries = (status == TX_FAIL_RETRY);
- tx_status->retry_count = retry;
rt2x00dev->link.qual.tx_success += success;
- rt2x00dev->link.qual.tx_failed += retry + fail;
+ rt2x00dev->link.qual.tx_failed += txdesc->retry + fail;
+
+ /*
+ * Initialize TX status
+ */
+ tx_status.flags = 0;
+ tx_status.ack_signal = 0;
+ tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY);
+ tx_status.retry_count = txdesc->retry;
+ memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control));
- if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
if (success)
- tx_status->flags |= IEEE80211_TX_STATUS_ACK;
+ tx_status.flags |= IEEE80211_TX_STATUS_ACK;
else
- stats->dot11ACKFailureCount++;
+ rt2x00dev->low_level_stats.dot11ACKFailureCount++;
}
- tx_status->queue_length = entry->ring->stats.limit;
- tx_status->queue_number = tx_status->control.queue;
+ tx_status.queue_length = entry->queue->limit;
+ tx_status.queue_number = tx_status.control.queue;
- if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) {
if (success)
- stats->dot11RTSSuccessCount++;
+ rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
else
- stats->dot11RTSFailureCount++;
+ rt2x00dev->low_level_stats.dot11RTSFailureCount++;
}
/*
- * Send the tx_status to mac80211 & debugfs.
- * mac80211 will clean up the skb structure.
+ * Send the tx_status to debugfs. Only send the status report
+ * to mac80211 when the frame originated from there. If this was
+ * a extra frame coming through a mac80211 library call (RTS/CTS)
+ * then we should not send the status report back.
+ * If send to mac80211, mac80211 will clean up the skb structure,
+ * otherwise we have to do it ourself.
*/
- get_skb_desc(entry->skb)->frame_type = DUMP_FRAME_TXDONE;
+ skbdesc = get_skb_frame_desc(entry->skb);
+ skbdesc->frame_type = DUMP_FRAME_TXDONE;
+
rt2x00debug_dump_frame(rt2x00dev, entry->skb);
- ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status);
+
+ if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED))
+ ieee80211_tx_status_irqsafe(rt2x00dev->hw,
+ entry->skb, &tx_status);
+ else
+ dev_kfree_skb(entry->skb);
entry->skb = NULL;
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
-void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
- struct rxdata_entry_desc *desc)
+void rt2x00lib_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
{
- struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
- struct ieee80211_hw_mode *mode;
- struct ieee80211_rate *rate;
+ struct ieee80211_supported_band *sband;
struct ieee80211_hdr *hdr;
+ const struct rt2x00_rate *rate;
unsigned int i;
- int val = 0;
+ int idx = -1;
u16 fc;
/*
* Update RX statistics.
*/
- mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode];
- for (i = 0; i < mode->num_rates; i++) {
- rate = &mode->rates[i];
+ sband = &rt2x00dev->bands[rt2x00dev->curr_band];
+ for (i = 0; i < sband->n_bitrates; i++) {
+ rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
- /*
- * When frame was received with an OFDM bitrate,
- * the signal is the PLCP value. If it was received with
- * a CCK bitrate the signal is the rate in 0.5kbit/s.
- */
- if (!desc->ofdm)
- val = DEVICE_GET_RATE_FIELD(rate->val, RATE);
- else
- val = DEVICE_GET_RATE_FIELD(rate->val, PLCP);
-
- if (val == desc->signal) {
- val = rate->val;
+ if ((rxdesc->signal_plcp && rate->plcp == rxdesc->signal) ||
+ (!rxdesc->signal_plcp && rate->bitrate == rxdesc->signal)) {
+ idx = i;
break;
}
}
/*
* Only update link status if this is a beacon frame carrying our bssid.
*/
- hdr = (struct ieee80211_hdr*)skb->data;
+ hdr = (struct ieee80211_hdr *)entry->skb->data;
fc = le16_to_cpu(hdr->frame_control);
- if (is_beacon(fc) && desc->my_bss)
- rt2x00lib_update_link_stats(&rt2x00dev->link, desc->rssi);
+ if (is_beacon(fc) && rxdesc->my_bss)
+ rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc->rssi);
rt2x00dev->link.qual.rx_success++;
- rx_status->rate = val;
+ rx_status->rate_idx = idx;
rx_status->signal =
- rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi);
- rx_status->ssi = desc->rssi;
- rx_status->flag = desc->flags;
+ rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi);
+ rx_status->ssi = rxdesc->rssi;
+ rx_status->flag = rxdesc->flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx;
/*
- * Send frame to mac80211 & debugfs
+ * Send frame to mac80211 & debugfs.
+ * mac80211 will clean up the skb structure.
*/
- get_skb_desc(skb)->frame_type = DUMP_FRAME_RXDONE;
- rt2x00debug_dump_frame(rt2x00dev, skb);
- ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status);
+ get_skb_frame_desc(entry->skb)->frame_type = DUMP_FRAME_RXDONE;
+ rt2x00debug_dump_frame(rt2x00dev, entry->skb);
+ ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
+ entry->skb = NULL;
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
struct sk_buff *skb,
struct ieee80211_tx_control *control)
{
- struct txdata_entry_desc desc;
- struct skb_desc *skbdesc = get_skb_desc(skb);
- struct ieee80211_hdr *ieee80211hdr = skbdesc->data;
+ struct txentry_desc txdesc;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data;
+ const struct rt2x00_rate *rate;
int tx_rate;
- int bitrate;
int length;
int duration;
int residual;
u16 frame_control;
u16 seq_ctrl;
- memset(&desc, 0, sizeof(desc));
-
- desc.cw_min = skbdesc->ring->tx_params.cw_min;
- desc.cw_max = skbdesc->ring->tx_params.cw_max;
- desc.aifs = skbdesc->ring->tx_params.aifs;
+ memset(&txdesc, 0, sizeof(txdesc));
- /*
- * Identify queue
- */
- if (control->queue < rt2x00dev->hw->queues)
- desc.queue = control->queue;
- else if (control->queue == IEEE80211_TX_QUEUE_BEACON ||
- control->queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
- desc.queue = QUEUE_MGMT;
- else
- desc.queue = QUEUE_OTHER;
+ txdesc.queue = skbdesc->entry->queue->qid;
+ txdesc.cw_min = skbdesc->entry->queue->cw_min;
+ txdesc.cw_max = skbdesc->entry->queue->cw_max;
+ txdesc.aifs = skbdesc->entry->queue->aifs;
/*
* Read required fields from ieee80211 header.
*/
- frame_control = le16_to_cpu(ieee80211hdr->frame_control);
- seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl);
+ frame_control = le16_to_cpu(hdr->frame_control);
+ seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
- tx_rate = control->tx_rate;
+ tx_rate = control->tx_rate->hw_value;
/*
* Check whether this frame is to be acked
*/
if (!(control->flags & IEEE80211_TXCTL_NO_ACK))
- __set_bit(ENTRY_TXD_ACK, &desc.flags);
+ __set_bit(ENTRY_TXD_ACK, &txdesc.flags);
/*
* Check if this is a RTS/CTS frame
*/
if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
- __set_bit(ENTRY_TXD_BURST, &desc.flags);
+ __set_bit(ENTRY_TXD_BURST, &txdesc.flags);
if (is_rts_frame(frame_control)) {
- __set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags);
- __set_bit(ENTRY_TXD_ACK, &desc.flags);
+ __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags);
+ __set_bit(ENTRY_TXD_ACK, &txdesc.flags);
} else
- __clear_bit(ENTRY_TXD_ACK, &desc.flags);
+ __clear_bit(ENTRY_TXD_ACK, &txdesc.flags);
if (control->rts_cts_rate)
- tx_rate = control->rts_cts_rate;
+ tx_rate = control->rts_cts_rate->hw_value;
}
- /*
- * Check for OFDM
- */
- if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATEMASK)
- __set_bit(ENTRY_TXD_OFDM_RATE, &desc.flags);
+ rate = rt2x00_get_rate(tx_rate);
/*
* Check if more fragments are pending
*/
- if (ieee80211_get_morefrag(ieee80211hdr)) {
- __set_bit(ENTRY_TXD_BURST, &desc.flags);
- __set_bit(ENTRY_TXD_MORE_FRAG, &desc.flags);
+ if (ieee80211_get_morefrag(hdr)) {
+ __set_bit(ENTRY_TXD_BURST, &txdesc.flags);
+ __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags);
}
/*
* Beacons and probe responses require the tsf timestamp
* to be inserted into the frame.
*/
- if (control->queue == IEEE80211_TX_QUEUE_BEACON ||
+ if (control->queue == RT2X00_BCN_QUEUE_BEACON ||
is_probe_resp(frame_control))
- __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc.flags);
+ __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags);
/*
* Determine with what IFS priority this frame should be send.
* or this fragment came after RTS/CTS.
*/
if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 ||
- test_bit(ENTRY_TXD_RTS_FRAME, &desc.flags))
- desc.ifs = IFS_SIFS;
+ test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags))
+ txdesc.ifs = IFS_SIFS;
else
- desc.ifs = IFS_BACKOFF;
+ txdesc.ifs = IFS_BACKOFF;
/*
* PLCP setup
* Length calculation depends on OFDM/CCK rate.
*/
- desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
- desc.service = 0x04;
+ txdesc.signal = rate->plcp;
+ txdesc.service = 0x04;
length = skbdesc->data_len + FCS_LEN;
- if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) {
- desc.length_high = (length >> 6) & 0x3f;
- desc.length_low = length & 0x3f;
- } else {
- bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
+ if (rate->flags & DEV_RATE_OFDM) {
+ __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags);
+ txdesc.length_high = (length >> 6) & 0x3f;
+ txdesc.length_low = length & 0x3f;
+ } else {
/*
* Convert length to microseconds.
*/
- residual = get_duration_res(length, bitrate);
- duration = get_duration(length, bitrate);
+ residual = get_duration_res(length, rate->bitrate);
+ duration = get_duration(length, rate->bitrate);
if (residual != 0) {
duration++;
/*
* Check if we need to set the Length Extension
*/
- if (bitrate == 110 && residual <= 30)
- desc.service |= 0x80;
+ if (rate->bitrate == 110 && residual <= 30)
+ txdesc.service |= 0x80;
}
- desc.length_high = (duration >> 8) & 0xff;
- desc.length_low = duration & 0xff;
+ txdesc.length_high = (duration >> 8) & 0xff;
+ txdesc.length_low = duration & 0xff;
/*
* When preamble is enabled we should set the
* preamble bit for the signal.
*/
- if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
- desc.signal |= 0x08;
+ if (rt2x00_get_rate_preamble(tx_rate))
+ txdesc.signal |= 0x08;
}
- rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &desc, control);
+ rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc, control);
/*
- * Update ring entry.
+ * Update queue entry.
*/
skbdesc->entry->skb = skb;
- memcpy(&skbdesc->entry->tx_status.control, control, sizeof(*control));
/*
* The frame has been completely initialized and ready
/*
* Driver initialization handlers.
*/
+const struct rt2x00_rate rt2x00_supported_rates[12] = {
+ {
+ .flags = DEV_RATE_CCK | DEV_RATE_BASIC,
+ .bitrate = 10,
+ .ratemask = BIT(0),
+ .plcp = 0x00,
+ },
+ {
+ .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+ .bitrate = 20,
+ .ratemask = BIT(1),
+ .plcp = 0x01,
+ },
+ {
+ .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+ .bitrate = 55,
+ .ratemask = BIT(2),
+ .plcp = 0x02,
+ },
+ {
+ .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+ .bitrate = 110,
+ .ratemask = BIT(3),
+ .plcp = 0x03,
+ },
+ {
+ .flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+ .bitrate = 60,
+ .ratemask = BIT(4),
+ .plcp = 0x0b,
+ },
+ {
+ .flags = DEV_RATE_OFDM,
+ .bitrate = 90,
+ .ratemask = BIT(5),
+ .plcp = 0x0f,
+ },
+ {
+ .flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+ .bitrate = 120,
+ .ratemask = BIT(6),
+ .plcp = 0x0a,
+ },
+ {
+ .flags = DEV_RATE_OFDM,
+ .bitrate = 180,
+ .ratemask = BIT(7),
+ .plcp = 0x0e,
+ },
+ {
+ .flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+ .bitrate = 240,
+ .ratemask = BIT(8),
+ .plcp = 0x09,
+ },
+ {
+ .flags = DEV_RATE_OFDM,
+ .bitrate = 360,
+ .ratemask = BIT(9),
+ .plcp = 0x0d,
+ },
+ {
+ .flags = DEV_RATE_OFDM,
+ .bitrate = 480,
+ .ratemask = BIT(10),
+ .plcp = 0x08,
+ },
+ {
+ .flags = DEV_RATE_OFDM,
+ .bitrate = 540,
+ .ratemask = BIT(11),
+ .plcp = 0x0c,
+ },
+};
+
static void rt2x00lib_channel(struct ieee80211_channel *entry,
const int channel, const int tx_power,
const int value)
{
- entry->chan = channel;
- if (channel <= 14)
- entry->freq = 2407 + (5 * channel);
- else
- entry->freq = 5000 + (5 * channel);
- entry->val = value;
- entry->flag =
- IEEE80211_CHAN_W_IBSS |
- IEEE80211_CHAN_W_ACTIVE_SCAN |
- IEEE80211_CHAN_W_SCAN;
- entry->power_level = tx_power;
- entry->antenna_max = 0xff;
+ entry->center_freq = ieee80211_channel_to_frequency(channel);
+ entry->hw_value = value;
+ entry->max_power = tx_power;
+ entry->max_antenna_gain = 0xff;
}
static void rt2x00lib_rate(struct ieee80211_rate *entry,
- const int rate, const int mask,
- const int plcp, const int flags)
+ const u16 index, const struct rt2x00_rate *rate)
{
- entry->rate = rate;
- entry->val =
- DEVICE_SET_RATE_FIELD(rate, RATE) |
- DEVICE_SET_RATE_FIELD(mask, RATEMASK) |
- DEVICE_SET_RATE_FIELD(plcp, PLCP);
- entry->flags = flags;
- entry->val2 = entry->val;
- if (entry->flags & IEEE80211_RATE_PREAMBLE2)
- entry->val2 |= DEVICE_SET_RATE_FIELD(1, PREAMBLE);
- entry->min_rssi_ack = 0;
- entry->min_rssi_ack_delta = 0;
+ entry->flags = 0;
+ entry->bitrate = rate->bitrate;
+ entry->hw_value = rt2x00_create_rate_hw_value(index, 0);
+ entry->hw_value_short = entry->hw_value;
+
+ if (rate->flags & DEV_RATE_SHORT_PREAMBLE) {
+ entry->flags |= IEEE80211_RATE_SHORT_PREAMBLE;
+ entry->hw_value_short |= rt2x00_create_rate_hw_value(index, 1);
+ }
}
static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
struct hw_mode_spec *spec)
{
struct ieee80211_hw *hw = rt2x00dev->hw;
- struct ieee80211_hw_mode *hwmodes;
struct ieee80211_channel *channels;
struct ieee80211_rate *rates;
+ unsigned int num_rates;
unsigned int i;
unsigned char tx_power;
- hwmodes = kzalloc(sizeof(*hwmodes) * spec->num_modes, GFP_KERNEL);
- if (!hwmodes)
- goto exit;
+ num_rates = 0;
+ if (spec->supported_rates & SUPPORT_RATE_CCK)
+ num_rates += 4;
+ if (spec->supported_rates & SUPPORT_RATE_OFDM)
+ num_rates += 8;
channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL);
if (!channels)
- goto exit_free_modes;
+ return -ENOMEM;
- rates = kzalloc(sizeof(*rates) * spec->num_rates, GFP_KERNEL);
+ rates = kzalloc(sizeof(*rates) * num_rates, GFP_KERNEL);
if (!rates)
goto exit_free_channels;
/*
* Initialize Rate list.
*/
- rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB,
- 0x00, IEEE80211_RATE_CCK);
- rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB,
- 0x01, IEEE80211_RATE_CCK_2);
- rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB,
- 0x02, IEEE80211_RATE_CCK_2);
- rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB,
- 0x03, IEEE80211_RATE_CCK_2);
-
- if (spec->num_rates > 4) {
- rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB,
- 0x0b, IEEE80211_RATE_OFDM);
- rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB,
- 0x0f, IEEE80211_RATE_OFDM);
- rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB,
- 0x0a, IEEE80211_RATE_OFDM);
- rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB,
- 0x0e, IEEE80211_RATE_OFDM);
- rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB,
- 0x09, IEEE80211_RATE_OFDM);
- rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB,
- 0x0d, IEEE80211_RATE_OFDM);
- rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB,
- 0x08, IEEE80211_RATE_OFDM);
- rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB,
- 0x0c, IEEE80211_RATE_OFDM);
- }
+ for (i = 0; i < num_rates; i++)
+ rt2x00lib_rate(&rates[i], i, rt2x00_get_rate(i));
/*
* Initialize Channel list.
*/
for (i = 0; i < spec->num_channels; i++) {
- if (spec->channels[i].channel <= 14)
- tx_power = spec->tx_power_bg[i];
- else if (spec->tx_power_a)
- tx_power = spec->tx_power_a[i];
- else
- tx_power = spec->tx_power_default;
+ if (spec->channels[i].channel <= 14) {
+ if (spec->tx_power_bg)
+ tx_power = spec->tx_power_bg[i];
+ else
+ tx_power = spec->tx_power_default;
+ } else {
+ if (spec->tx_power_a)
+ tx_power = spec->tx_power_a[i];
+ else
+ tx_power = spec->tx_power_default;
+ }
rt2x00lib_channel(&channels[i],
spec->channels[i].channel, tx_power, i);
}
/*
- * Intitialize 802.11b
- * Rates: CCK.
- * Channels: OFDM.
- */
- if (spec->num_modes > HWMODE_B) {
- hwmodes[HWMODE_B].mode = MODE_IEEE80211B;
- hwmodes[HWMODE_B].num_channels = 14;
- hwmodes[HWMODE_B].num_rates = 4;
- hwmodes[HWMODE_B].channels = channels;
- hwmodes[HWMODE_B].rates = rates;
- }
-
- /*
- * Intitialize 802.11g
+ * Intitialize 802.11b, 802.11g
* Rates: CCK, OFDM.
- * Channels: OFDM.
- */
- if (spec->num_modes > HWMODE_G) {
- hwmodes[HWMODE_G].mode = MODE_IEEE80211G;
- hwmodes[HWMODE_G].num_channels = 14;
- hwmodes[HWMODE_G].num_rates = spec->num_rates;
- hwmodes[HWMODE_G].channels = channels;
- hwmodes[HWMODE_G].rates = rates;
+ * Channels: 2.4 GHz
+ */
+ if (spec->supported_bands & SUPPORT_BAND_2GHZ) {
+ rt2x00dev->bands[IEEE80211_BAND_2GHZ].n_channels = 14;
+ rt2x00dev->bands[IEEE80211_BAND_2GHZ].n_bitrates = num_rates;
+ rt2x00dev->bands[IEEE80211_BAND_2GHZ].channels = channels;
+ rt2x00dev->bands[IEEE80211_BAND_2GHZ].bitrates = rates;
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &rt2x00dev->bands[IEEE80211_BAND_2GHZ];
}
/*
* Rates: OFDM.
* Channels: OFDM, UNII, HiperLAN2.
*/
- if (spec->num_modes > HWMODE_A) {
- hwmodes[HWMODE_A].mode = MODE_IEEE80211A;
- hwmodes[HWMODE_A].num_channels = spec->num_channels - 14;
- hwmodes[HWMODE_A].num_rates = spec->num_rates - 4;
- hwmodes[HWMODE_A].channels = &channels[14];
- hwmodes[HWMODE_A].rates = &rates[4];
+ if (spec->supported_bands & SUPPORT_BAND_5GHZ) {
+ rt2x00dev->bands[IEEE80211_BAND_5GHZ].n_channels =
+ spec->num_channels - 14;
+ rt2x00dev->bands[IEEE80211_BAND_5GHZ].n_bitrates =
+ num_rates - 4;
+ rt2x00dev->bands[IEEE80211_BAND_5GHZ].channels = &channels[14];
+ rt2x00dev->bands[IEEE80211_BAND_5GHZ].bitrates = &rates[4];
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &rt2x00dev->bands[IEEE80211_BAND_5GHZ];
}
- if (spec->num_modes > HWMODE_G &&
- ieee80211_register_hwmode(hw, &hwmodes[HWMODE_G]))
- goto exit_free_rates;
-
- if (spec->num_modes > HWMODE_B &&
- ieee80211_register_hwmode(hw, &hwmodes[HWMODE_B]))
- goto exit_free_rates;
-
- if (spec->num_modes > HWMODE_A &&
- ieee80211_register_hwmode(hw, &hwmodes[HWMODE_A]))
- goto exit_free_rates;
-
- rt2x00dev->hwmodes = hwmodes;
-
return 0;
-exit_free_rates:
- kfree(rates);
-
-exit_free_channels:
+ exit_free_channels:
kfree(channels);
-
-exit_free_modes:
- kfree(hwmodes);
-
-exit:
ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n");
return -ENOMEM;
}
if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags))
ieee80211_unregister_hw(rt2x00dev->hw);
- if (likely(rt2x00dev->hwmodes)) {
- kfree(rt2x00dev->hwmodes->channels);
- kfree(rt2x00dev->hwmodes->rates);
- kfree(rt2x00dev->hwmodes);
- rt2x00dev->hwmodes = NULL;
+ if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) {
+ kfree(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
+ kfree(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->bitrates);
+ rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+ rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
}
}
/*
* Initialization/uninitialization handlers.
*/
-static int rt2x00lib_alloc_entries(struct data_ring *ring,
- const u16 max_entries, const u16 data_size,
- const u16 desc_size)
-{
- struct data_entry *entry;
- unsigned int i;
-
- ring->stats.limit = max_entries;
- ring->data_size = data_size;
- ring->desc_size = desc_size;
-
- /*
- * Allocate all ring entries.
- */
- entry = kzalloc(ring->stats.limit * sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- for (i = 0; i < ring->stats.limit; i++) {
- entry[i].flags = 0;
- entry[i].ring = ring;
- entry[i].skb = NULL;
- entry[i].entry_idx = i;
- }
-
- ring->entry = entry;
-
- return 0;
-}
-
-static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev)
-{
- struct data_ring *ring;
-
- /*
- * Allocate the RX ring.
- */
- if (rt2x00lib_alloc_entries(rt2x00dev->rx, RX_ENTRIES, DATA_FRAME_SIZE,
- rt2x00dev->ops->rxd_size))
- return -ENOMEM;
-
- /*
- * First allocate the TX rings.
- */
- txring_for_each(rt2x00dev, ring) {
- if (rt2x00lib_alloc_entries(ring, TX_ENTRIES, DATA_FRAME_SIZE,
- rt2x00dev->ops->txd_size))
- return -ENOMEM;
- }
-
- if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
- return 0;
-
- /*
- * Allocate the BEACON ring.
- */
- if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[0], BEACON_ENTRIES,
- MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size))
- return -ENOMEM;
-
- /*
- * Allocate the Atim ring.
- */
- if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[1], ATIM_ENTRIES,
- DATA_FRAME_SIZE, rt2x00dev->ops->txd_size))
- return -ENOMEM;
-
- return 0;
-}
-
-static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev)
-{
- struct data_ring *ring;
-
- ring_for_each(rt2x00dev, ring) {
- kfree(ring->entry);
- ring->entry = NULL;
- }
-}
-
static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
{
if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
rt2x00dev->ops->lib->uninitialize(rt2x00dev);
/*
- * Free allocated ring entries.
+ * Free allocated queue entries.
*/
- rt2x00lib_free_ring_entries(rt2x00dev);
+ rt2x00queue_uninitialize(rt2x00dev);
}
static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
return 0;
/*
- * Allocate all ring entries.
+ * Allocate all queue entries.
*/
- status = rt2x00lib_alloc_ring_entries(rt2x00dev);
- if (status) {
- ERROR(rt2x00dev, "Ring entries allocation failed.\n");
+ status = rt2x00queue_initialize(rt2x00dev);
+ if (status)
return status;
- }
/*
* Initialize the device.
return 0;
-exit_unitialize:
- rt2x00lib_uninitialize(rt2x00dev);
-
exit:
- rt2x00lib_free_ring_entries(rt2x00dev);
+ rt2x00lib_uninitialize(rt2x00dev);
return status;
}
* If this is the first interface which is added,
* we should load the firmware now.
*/
- if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
- retval = rt2x00lib_load_firmware(rt2x00dev);
- if (retval)
- return retval;
- }
+ retval = rt2x00lib_load_firmware(rt2x00dev);
+ if (retval)
+ return retval;
/*
* Initialize the device.
return retval;
}
+ rt2x00dev->intf_ap_count = 0;
+ rt2x00dev->intf_sta_count = 0;
+ rt2x00dev->intf_associated = 0;
+
__set_bit(DEVICE_STARTED, &rt2x00dev->flags);
return 0;
*/
rt2x00lib_disable_radio(rt2x00dev);
+ rt2x00dev->intf_ap_count = 0;
+ rt2x00dev->intf_sta_count = 0;
+ rt2x00dev->intf_associated = 0;
+
__clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
}
/*
* driver allocation handlers.
*/
-static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev)
+int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
{
- struct data_ring *ring;
- unsigned int index;
-
- /*
- * We need the following rings:
- * RX: 1
- * TX: hw->queues
- * Beacon: 1 (if required)
- * Atim: 1 (if required)
- */
- rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues +
- (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags));
-
- ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL);
- if (!ring) {
- ERROR(rt2x00dev, "Ring allocation failed.\n");
- return -ENOMEM;
- }
+ int retval = -ENOMEM;
/*
- * Initialize pointers
+ * Make room for rt2x00_intf inside the per-interface
+ * structure ieee80211_vif.
*/
- rt2x00dev->rx = ring;
- rt2x00dev->tx = &rt2x00dev->rx[1];
- if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
- rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues];
-
- /*
- * Initialize ring parameters.
- * RX: queue_idx = 0
- * TX: queue_idx = IEEE80211_TX_QUEUE_DATA0 + index
- * TX: cw_min: 2^5 = 32.
- * TX: cw_max: 2^10 = 1024.
- */
- rt2x00dev->rx->rt2x00dev = rt2x00dev;
- rt2x00dev->rx->queue_idx = 0;
-
- index = IEEE80211_TX_QUEUE_DATA0;
- txring_for_each(rt2x00dev, ring) {
- ring->rt2x00dev = rt2x00dev;
- ring->queue_idx = index++;
- ring->tx_params.aifs = 2;
- ring->tx_params.cw_min = 5;
- ring->tx_params.cw_max = 10;
- }
-
- return 0;
-}
-
-static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev)
-{
- kfree(rt2x00dev->rx);
- rt2x00dev->rx = NULL;
- rt2x00dev->tx = NULL;
- rt2x00dev->bcn = NULL;
-}
-
-int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
-{
- int retval = -ENOMEM;
+ rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
/*
* Let the driver probe the device to detect the capabilities.
/*
* Initialize configuration work.
*/
- INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled);
+ INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
- INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled);
INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
/*
- * Reset current working type.
- */
- rt2x00dev->interface.type = IEEE80211_IF_TYPE_INVALID;
-
- /*
- * Allocate ring array.
+ * Allocate queue array.
*/
- retval = rt2x00lib_alloc_rings(rt2x00dev);
+ retval = rt2x00queue_allocate(rt2x00dev);
if (retval)
goto exit;
/*
* Register extra components.
*/
+ rt2x00leds_register(rt2x00dev);
rt2x00rfkill_allocate(rt2x00dev);
rt2x00debug_register(rt2x00dev);
rt2x00rfkill_free(rt2x00dev);
/*
+ * Free LED.
+ */
+ rt2x00leds_unregister(rt2x00dev);
+
+ /*
* Free ieee80211_hw memory.
*/
rt2x00lib_remove_hw(rt2x00dev);
rt2x00lib_free_firmware(rt2x00dev);
/*
- * Free ring structures.
+ * Free queue structures.
*/
- rt2x00lib_free_rings(rt2x00dev);
+ rt2x00queue_free(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
/*
* Suspend/disable extra components.
*/
+ rt2x00leds_suspend(rt2x00dev);
rt2x00rfkill_suspend(rt2x00dev);
rt2x00debug_deregister(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_suspend);
+static void rt2x00lib_resume_intf(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct rt2x00_dev *rt2x00dev = data;
+ struct rt2x00_intf *intf = vif_to_intf(vif);
+
+ spin_lock(&intf->lock);
+
+ rt2x00lib_config_intf(rt2x00dev, intf,
+ vif->type, intf->mac, intf->bssid);
+
+
+ /*
+ * Master or Ad-hoc mode require a new beacon update.
+ */
+ if (vif->type == IEEE80211_IF_TYPE_AP ||
+ vif->type == IEEE80211_IF_TYPE_IBSS)
+ intf->delayed_flags |= DELAYED_UPDATE_BEACON;
+
+ spin_unlock(&intf->lock);
+}
+
int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
{
- struct interface *intf = &rt2x00dev->interface;
int retval;
NOTICE(rt2x00dev, "Waking up.\n");
*/
rt2x00debug_register(rt2x00dev);
rt2x00rfkill_resume(rt2x00dev);
+ rt2x00leds_resume(rt2x00dev);
/*
* Only continue if mac80211 had open interfaces.
if (!rt2x00dev->hw->conf.radio_enabled)
rt2x00lib_disable_radio(rt2x00dev);
- rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
- rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
- rt2x00lib_config_type(rt2x00dev, intf->type);
+ /*
+ * Iterator over each active interface to
+ * reconfigure the hardware.
+ */
+ ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+ rt2x00lib_resume_intf, rt2x00dev);
/*
* We are ready again to receive requests from mac80211.
ieee80211_start_queues(rt2x00dev->hw);
/*
- * When in Master or Ad-hoc mode,
- * restart Beacon transmitting by faking a beacondone event.
+ * During interface iteration we might have changed the
+ * delayed_flags, time to handles the event by calling
+ * the work handler directly.
*/
- if (intf->type == IEEE80211_IF_TYPE_AP ||
- intf->type == IEEE80211_IF_TYPE_IBSS)
- rt2x00lib_beacondone(rt2x00dev);
+ rt2x00lib_intf_scheduled(&rt2x00dev->intf_work);
return 0;
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
* @chip_rf: RF chipset
* @chip_rev: Chipset revision
* @type: The frame type (&rt2x00_dump_type)
- * @ring_index: The index number of the data ring.
- * @entry_index: The index number of the entry inside the data ring.
+ * @queue_index: The index number of the data queue.
+ * @entry_index: The index number of the entry inside the data queue.
* @timestamp_sec: Timestamp - seconds
* @timestamp_usec: Timestamp - microseconds
*/
__le32 chip_rev;
__le16 type;
- __u8 ring_index;
+ __u8 queue_index;
__u8 entry_index;
__le32 timestamp_sec;
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
Abstract: rt2x00 firmware loading routines.
*/
-#include <linux/crc-itu-t.h>
#include <linux/kernel.h>
#include <linux/module.h>
char *fw_name;
int retval;
u16 crc;
- u16 tmp;
/*
* Read correct firmware from harddisk.
return -ENOENT;
}
- /*
- * Validate the firmware using 16 bit CRC.
- * The last 2 bytes of the firmware are the CRC
- * so substract those 2 bytes from the CRC checksum,
- * and set those 2 bytes to 0 when calculating CRC.
- */
- tmp = 0;
- crc = crc_itu_t(0, fw->data, fw->size - 2);
- crc = crc_itu_t(crc, (u8 *)&tmp, 2);
-
+ crc = rt2x00dev->ops->lib->get_firmware_crc(fw->data, fw->size);
if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) {
- ERROR(rt2x00dev, "Firmware CRC error.\n");
+ ERROR(rt2x00dev, "Firmware checksum error.\n");
retval = -ENOENT;
goto exit;
}
{
int retval;
+ if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags))
+ return 0;
+
if (!rt2x00dev->fw) {
retval = rt2x00lib_request_firmware(rt2x00dev);
if (retval)
release_firmware(rt2x00dev->fw);
rt2x00dev->fw = NULL;
}
-
--- /dev/null
+/*
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ 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.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 led specific routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi)
+{
+ if (!rt2x00dev->trigger_qual.registered)
+ return;
+
+ /*
+ * Led handling requires a positive value for the rssi,
+ * to do that correctly we need to add the correction.
+ */
+ rssi += rt2x00dev->rssi_offset;
+
+ /*
+ * Get the rssi level, this is used to convert the rssi
+ * to a LED value inside the range LED_OFF - LED_FULL.
+ */
+ if (rssi <= 30)
+ rssi = 0;
+ else if (rssi <= 39)
+ rssi = 1;
+ else if (rssi <= 49)
+ rssi = 2;
+ else if (rssi <= 53)
+ rssi = 3;
+ else if (rssi <= 63)
+ rssi = 4;
+ else
+ rssi = 5;
+
+ /*
+ * Note that we must _not_ send LED_OFF since the driver
+ * is going to calculate the value and might use it in a
+ * division.
+ */
+ led_trigger_event(&rt2x00dev->trigger_qual.trigger,
+ ((LED_FULL / 6) * rssi) + 1);
+}
+
+static int rt2x00leds_register_trigger(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_trigger *trigger,
+ const char *name)
+{
+ int retval;
+
+ trigger->trigger.name = name;
+ retval = led_trigger_register(&trigger->trigger);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to register led trigger.\n");
+ return retval;
+ }
+
+ trigger->registered = 1;
+
+ return 0;
+}
+
+static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_led *led,
+ enum led_type type,
+ const char *name, char *trigger)
+{
+ struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
+ int retval;
+
+ led->led_dev.name = name;
+ led->led_dev.brightness_set = rt2x00dev->ops->lib->led_brightness;
+ led->led_dev.default_trigger = trigger;
+
+ retval = led_classdev_register(device, &led->led_dev);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to register led handler.\n");
+ return retval;
+ }
+
+ led->rt2x00dev = rt2x00dev;
+ led->type = type;
+ led->registered = 1;
+
+ return 0;
+}
+
+void rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
+{
+ char *trigger;
+ char dev_name[16];
+ char name[32];
+ int retval;
+
+ if (!rt2x00dev->ops->lib->led_brightness)
+ return;
+
+ snprintf(dev_name, sizeof(dev_name), "%s-%s",
+ rt2x00dev->ops->name, wiphy_name(rt2x00dev->hw->wiphy));
+
+ if (rt2x00dev->led_flags & LED_SUPPORT_RADIO) {
+ trigger = ieee80211_get_radio_led_name(rt2x00dev->hw);
+ snprintf(name, sizeof(name), "%s:radio", dev_name);
+
+ retval = rt2x00leds_register_led(rt2x00dev,
+ &rt2x00dev->led_radio,
+ LED_TYPE_RADIO,
+ name, trigger);
+ if (retval)
+ goto exit_fail;
+ }
+
+ if (rt2x00dev->led_flags & LED_SUPPORT_ASSOC) {
+ trigger = ieee80211_get_assoc_led_name(rt2x00dev->hw);
+ snprintf(name, sizeof(name), "%s:assoc", dev_name);
+
+ retval = rt2x00leds_register_led(rt2x00dev,
+ &rt2x00dev->led_assoc,
+ LED_TYPE_ASSOC,
+ name, trigger);
+ if (retval)
+ goto exit_fail;
+ }
+
+ if (rt2x00dev->led_flags & LED_SUPPORT_QUALITY) {
+ snprintf(name, sizeof(name), "%s:quality", dev_name);
+
+ retval = rt2x00leds_register_trigger(rt2x00dev,
+ &rt2x00dev->trigger_qual,
+ name);
+
+ retval = rt2x00leds_register_led(rt2x00dev,
+ &rt2x00dev->led_qual,
+ LED_TYPE_QUALITY,
+ name, name);
+ if (retval)
+ goto exit_fail;
+ }
+
+ return;
+
+exit_fail:
+ rt2x00leds_unregister(rt2x00dev);
+}
+
+static void rt2x00leds_unregister_trigger(struct rt2x00_trigger *trigger)
+{
+ if (!trigger->registered)
+ return;
+
+ led_trigger_unregister(&trigger->trigger);
+ trigger->registered = 0;
+}
+
+static void rt2x00leds_unregister_led(struct rt2x00_led *led)
+{
+ if (!led->registered)
+ return;
+
+ led_classdev_unregister(&led->led_dev);
+
+ led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+ led->registered = 0;
+}
+
+void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
+{
+ rt2x00leds_unregister_trigger(&rt2x00dev->trigger_qual);
+ rt2x00leds_unregister_led(&rt2x00dev->led_qual);
+ rt2x00leds_unregister_led(&rt2x00dev->led_assoc);
+ rt2x00leds_unregister_led(&rt2x00dev->led_radio);
+}
+
+void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
+{
+ if (rt2x00dev->led_qual.registered)
+ led_classdev_suspend(&rt2x00dev->led_qual.led_dev);
+ if (rt2x00dev->led_assoc.registered)
+ led_classdev_suspend(&rt2x00dev->led_assoc.led_dev);
+ if (rt2x00dev->led_radio.registered)
+ led_classdev_suspend(&rt2x00dev->led_radio.led_dev);
+}
+
+void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
+{
+ if (rt2x00dev->led_radio.registered)
+ led_classdev_resume(&rt2x00dev->led_radio.led_dev);
+ if (rt2x00dev->led_assoc.registered)
+ led_classdev_resume(&rt2x00dev->led_assoc.led_dev);
+ if (rt2x00dev->led_qual.registered)
+ led_classdev_resume(&rt2x00dev->led_qual.led_dev);
+}
--- /dev/null
+/*
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ 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.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 led datastructures and routines
+ */
+
+#ifndef RT2X00LEDS_H
+#define RT2X00LEDS_H
+
+/*
+* Flags used by driver to indicate which
+ * which led types are supported.
+ */
+#define LED_SUPPORT_RADIO 0x000001
+#define LED_SUPPORT_ASSOC 0x000002
+#define LED_SUPPORT_ACTIVITY 0x000004
+#define LED_SUPPORT_QUALITY 0x000008
+
+enum led_type {
+ LED_TYPE_RADIO,
+ LED_TYPE_ASSOC,
+ LED_TYPE_QUALITY,
+};
+
+#ifdef CONFIG_RT2X00_LIB_LEDS
+
+struct rt2x00_led {
+ struct rt2x00_dev *rt2x00dev;
+ struct led_classdev led_dev;
+
+ enum led_type type;
+ unsigned int registered;
+};
+
+struct rt2x00_trigger {
+ struct led_trigger trigger;
+
+ enum led_type type;
+ unsigned int registered;
+};
+
+#endif /* CONFIG_RT2X00_LIB_LEDS */
+
+#endif /* RT2X00LEDS_H */
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#define RFKILL_POLL_INTERVAL ( 1000 )
/*
+ * rt2x00_rate: Per rate device information
+ */
+struct rt2x00_rate {
+ unsigned short flags;
+#define DEV_RATE_CCK 0x0001
+#define DEV_RATE_OFDM 0x0002
+#define DEV_RATE_SHORT_PREAMBLE 0x0004
+#define DEV_RATE_BASIC 0x0008
+
+ unsigned short bitrate; /* In 100kbit/s */
+ unsigned short ratemask;
+
+ unsigned short plcp;
+};
+
+extern const struct rt2x00_rate rt2x00_supported_rates[12];
+
+static inline u16 rt2x00_create_rate_hw_value(const u16 index,
+ const u16 short_preamble)
+{
+ return (short_preamble << 8) | (index & 0xff);
+}
+
+static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value)
+{
+ return &rt2x00_supported_rates[hw_value & 0xff];
+}
+
+static inline int rt2x00_get_rate_preamble(const u16 hw_value)
+{
+ return (hw_value & 0xff00);
+}
+
+/*
* Radio control handlers.
*/
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev);
/*
* Configuration handlers.
*/
-void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
-void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
-void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type);
+void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ enum ieee80211_if_types type,
+ u8 *mac, u8 *bssid);
+void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct ieee80211_bss_conf *conf);
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
enum antenna rx, enum antenna tx);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf, const int force_config);
/*
+ * Queue handlers.
+ */
+void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev);
+void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
+int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev);
+int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev);
+void rt2x00queue_free(struct rt2x00_dev *rt2x00dev);
+
+/*
* Firmware handlers.
*/
#ifdef CONFIG_RT2X00_LIB_FIRMWARE
}
#endif /* CONFIG_RT2X00_LIB_RFKILL */
+/*
+ * LED handlers
+ */
+#ifdef CONFIG_RT2X00_LIB_LEDS
+void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi);
+void rt2x00leds_register(struct rt2x00_dev *rt2x00dev);
+void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev);
+void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev);
+void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev);
+#else
+static inline void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev,
+ int rssi)
+{
+}
+
+static inline void rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_LEDS */
+
#endif /* RT2X00LIB_H */
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#include "rt2x00lib.h"
static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring,
+ struct data_queue *queue,
struct sk_buff *frag_skb,
struct ieee80211_tx_control *control)
{
+ struct skb_frame_desc *skbdesc;
struct sk_buff *skb;
int size;
skb_put(skb, size);
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
- ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id,
+ ieee80211_ctstoself_get(rt2x00dev->hw, control->vif,
frag_skb->data, frag_skb->len, control,
(struct ieee80211_cts *)(skb->data));
else
- ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id,
+ ieee80211_rts_get(rt2x00dev->hw, control->vif,
frag_skb->data, frag_skb->len, control,
(struct ieee80211_rts *)(skb->data));
- if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
+ /*
+ * Initialize skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+ skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
+
+ if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
return NETDEV_TX_BUSY;
}
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
- struct data_ring *ring;
+ struct data_queue *queue;
+ struct skb_frame_desc *skbdesc;
u16 frame_control;
/*
}
/*
- * Determine which ring to put packet on.
+ * Determine which queue to put packet on.
*/
- ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
- if (unlikely(!ring)) {
+ if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM &&
+ test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
+ queue = rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
+ else
+ queue = rt2x00queue_get_queue(rt2x00dev, control->queue);
+ if (unlikely(!queue)) {
ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n"
"Please file bug report to %s.\n",
if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
(control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
IEEE80211_TXCTL_USE_CTS_PROTECT))) {
- if (rt2x00_ring_free(ring) <= 1) {
+ if (rt2x00queue_available(queue) <= 1) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
return NETDEV_TX_BUSY;
}
- if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) {
+ if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
return NETDEV_TX_BUSY;
}
}
- if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
+ /*
+ * Initialize skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+
+ if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
return NETDEV_TX_BUSY;
}
- if (rt2x00_ring_full(ring))
+ if (rt2x00queue_full(queue))
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
if (rt2x00dev->ops->lib->kick_tx_queue)
struct ieee80211_if_init_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct interface *intf = &rt2x00dev->interface;
-
- /* FIXME: Beaconing is broken in rt2x00. */
- if (conf->type == IEEE80211_IF_TYPE_IBSS ||
- conf->type == IEEE80211_IF_TYPE_AP) {
- ERROR(rt2x00dev,
- "rt2x00 does not support Adhoc or Master mode");
- return -EOPNOTSUPP;
- }
+ struct rt2x00_intf *intf = vif_to_intf(conf->vif);
+ struct data_queue *queue =
+ rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON);
+ struct queue_entry *entry = NULL;
+ unsigned int i;
/*
- * Don't allow interfaces to be added while
- * either the device has disappeared or when
- * another interface is already present.
+ * Don't allow interfaces to be added
+ * the device has disappeared.
*/
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
- is_interface_present(intf))
+ !test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ return -ENODEV;
+
+ /*
+ * When we don't support mixed interfaces (a combination
+ * of sta and ap virtual interfaces) then we can only
+ * add this interface when the rival interface count is 0.
+ */
+ if (!test_bit(DRIVER_SUPPORT_MIXED_INTERFACES, &rt2x00dev->flags) &&
+ ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) ||
+ (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count)))
return -ENOBUFS;
- intf->id = conf->vif;
- intf->type = conf->type;
+ /*
+ * Check if we exceeded the maximum amount of supported interfaces.
+ */
+ if ((conf->type == IEEE80211_IF_TYPE_AP &&
+ rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf) ||
+ (conf->type != IEEE80211_IF_TYPE_AP &&
+ rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf))
+ return -ENOBUFS;
+
+ /*
+ * Loop through all beacon queues to find a free
+ * entry. Since there are as much beacon entries
+ * as the maximum interfaces, this search shouldn't
+ * fail.
+ */
+ for (i = 0; i < queue->limit; i++) {
+ entry = &queue->entries[i];
+ if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags))
+ break;
+ }
+
+ if (unlikely(i == queue->limit))
+ return -ENOBUFS;
+
+ /*
+ * We are now absolutely sure the interface can be created,
+ * increase interface count and start initialization.
+ */
+
+ if (conf->type == IEEE80211_IF_TYPE_AP)
+ rt2x00dev->intf_ap_count++;
+ else
+ rt2x00dev->intf_sta_count++;
+
+ spin_lock_init(&intf->lock);
+ intf->beacon = entry;
+
if (conf->type == IEEE80211_IF_TYPE_AP)
memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
* has been initialized. Otherwise the device can reset
* the MAC registers.
*/
- rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
- rt2x00lib_config_type(rt2x00dev, conf->type);
+ rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL);
return 0;
}
struct ieee80211_if_init_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct interface *intf = &rt2x00dev->interface;
+ struct rt2x00_intf *intf = vif_to_intf(conf->vif);
/*
* Don't allow interfaces to be remove while
* no interface is present.
*/
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
- !is_interface_present(intf))
+ (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) ||
+ (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count))
return;
- intf->id = 0;
- intf->type = IEEE80211_IF_TYPE_INVALID;
- memset(&intf->bssid, 0x00, ETH_ALEN);
- memset(&intf->mac, 0x00, ETH_ALEN);
+ if (conf->type == IEEE80211_IF_TYPE_AP)
+ rt2x00dev->intf_ap_count--;
+ else
+ rt2x00dev->intf_sta_count--;
+
+ /*
+ * Release beacon entry so it is available for
+ * new interfaces again.
+ */
+ __clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags);
/*
* Make sure the bssid and mac address registers
* are cleared to prevent false ACKing of frames.
*/
- rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
- rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
- rt2x00lib_config_type(rt2x00dev, intf->type);
+ rt2x00lib_config_intf(rt2x00dev, intf,
+ IEEE80211_IF_TYPE_INVALID, NULL, NULL);
}
EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
struct ieee80211_if_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct interface *intf = &rt2x00dev->interface;
+ struct rt2x00_intf *intf = vif_to_intf(vif);
int status;
/*
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
return 0;
- /*
- * If the given type does not match the configured type,
- * there has been a problem.
- */
- if (conf->type != intf->type)
- return -EINVAL;
+ spin_lock(&intf->lock);
/*
* If the interface does not work in master mode,
*/
if (conf->type != IEEE80211_IF_TYPE_AP)
memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
- rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+
+ spin_unlock(&intf->lock);
+
+ /*
+ * Call rt2x00_config_intf() outside of the spinlock context since
+ * the call will sleep for USB drivers. By using the ieee80211_if_conf
+ * values as arguments we make keep access to rt2x00_intf thread safe
+ * even without the lock.
+ */
+ rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, conf->bssid);
/*
* We only need to initialize the beacon when master mode is enabled.
struct rt2x00_dev *rt2x00dev = hw->priv;
unsigned int i;
- for (i = 0; i < hw->queues; i++)
- memcpy(&stats->data[i], &rt2x00dev->tx[i].stats,
- sizeof(rt2x00dev->tx[i].stats));
+ for (i = 0; i < hw->queues; i++) {
+ stats->data[i].len = rt2x00dev->tx[i].length;
+ stats->data[i].limit = rt2x00dev->tx[i].limit;
+ stats->data[i].count = rt2x00dev->tx[i].count;
+ }
return 0;
}
u32 changes)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- int short_preamble;
- int ack_timeout;
- int ack_consume_time;
- int difs;
- int preamble;
+ struct rt2x00_intf *intf = vif_to_intf(vif);
/*
- * We only support changing preamble mode.
+ * When the association status has changed we must reset the link
+ * tuner counter. This is because some drivers determine if they
+ * should perform link tuning based on the number of seconds
+ * while associated or not associated.
*/
- if (!(changes & BSS_CHANGED_ERP_PREAMBLE))
- return;
-
- short_preamble = bss_conf->use_short_preamble;
- preamble = bss_conf->use_short_preamble ?
- SHORT_PREAMBLE : PREAMBLE;
+ if (changes & BSS_CHANGED_ASSOC) {
+ rt2x00dev->link.count = 0;
- difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ?
- SHORT_DIFS : DIFS;
- ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10);
-
- ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10);
+ if (bss_conf->assoc)
+ rt2x00dev->intf_associated++;
+ else
+ rt2x00dev->intf_associated--;
+ }
- if (short_preamble)
- __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
- else
- __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+ /*
+ * When the erp information has changed, we should perform
+ * additional configuration steps. For all other changes we are done.
+ */
+ if (changes & BSS_CHANGED_ERP_PREAMBLE)
+ rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
- rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble,
- ack_timeout, ack_consume_time);
+ spin_lock(&intf->lock);
+ memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
+ spin_unlock(&intf->lock);
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
-int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct data_ring *ring;
+ struct data_queue *queue;
- ring = rt2x00lib_get_ring(rt2x00dev, queue);
- if (unlikely(!ring))
+ queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+ if (unlikely(!queue))
return -EINVAL;
/*
* The passed variables are stored as real value ((2^n)-1).
* Ralink registers require to know the bit number 'n'.
*/
- if (params->cw_min)
- ring->tx_params.cw_min = fls(params->cw_min);
+ if (params->cw_min > 0)
+ queue->cw_min = fls(params->cw_min);
else
- ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */
+ queue->cw_min = 5; /* cw_min: 2^5 = 32. */
- if (params->cw_max)
- ring->tx_params.cw_max = fls(params->cw_max);
+ if (params->cw_max > 0)
+ queue->cw_max = fls(params->cw_max);
else
- ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */
+ queue->cw_max = 10; /* cw_min: 2^10 = 1024. */
- if (params->aifs)
- ring->tx_params.aifs = params->aifs;
+ if (params->aifs >= 0)
+ queue->aifs = params->aifs;
else
- ring->tx_params.aifs = 2;
+ queue->aifs = 2;
INFO(rt2x00dev,
- "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
- queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
- ring->tx_params.aifs);
+ "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
+ queue_idx, queue->cw_min, queue->cw_max, queue->aifs);
return 0;
}
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#include "rt2x00pci.h"
/*
- * Beacon handlers.
- */
-int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- struct skb_desc *desc;
- struct data_ring *ring;
- struct data_entry *entry;
-
- /*
- * Just in case mac80211 doesn't set this correctly,
- * but we need this queue set for the descriptor
- * initialization.
- */
- control->queue = IEEE80211_TX_QUEUE_BEACON;
- ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
- entry = rt2x00_get_data_entry(ring);
-
- /*
- * Fill in skb descriptor
- */
- desc = get_skb_desc(skb);
- desc->desc_len = ring->desc_size;
- desc->data_len = skb->len;
- desc->desc = entry->priv;
- desc->data = skb->data;
- desc->ring = ring;
- desc->entry = entry;
-
- memcpy(entry->data_addr, skb->data, skb->len);
- rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
-
- /*
- * Enable beacon generation.
- */
- rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update);
-
-/*
* TX data handlers.
*/
int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring, struct sk_buff *skb,
+ struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_tx_control *control)
{
- struct data_entry *entry = rt2x00_get_data_entry(ring);
- __le32 *txd = entry->priv;
- struct skb_desc *desc;
+ struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+ struct skb_frame_desc *skbdesc;
u32 word;
- if (rt2x00_ring_full(ring))
+ if (rt2x00queue_full(queue))
return -EINVAL;
- rt2x00_desc_read(txd, 0, &word);
+ rt2x00_desc_read(priv_tx->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
/*
* Fill in skb descriptor
*/
- desc = get_skb_desc(skb);
- desc->desc_len = ring->desc_size;
- desc->data_len = skb->len;
- desc->desc = entry->priv;
- desc->data = skb->data;
- desc->ring = ring;
- desc->entry = entry;
-
- memcpy(entry->data_addr, skb->data, skb->len);
+ skbdesc = get_skb_frame_desc(skb);
+ skbdesc->data = skb->data;
+ skbdesc->data_len = skb->len;
+ skbdesc->desc = priv_tx->desc;
+ skbdesc->desc_len = queue->desc_size;
+ skbdesc->entry = entry;
+
+ memcpy(&priv_tx->control, control, sizeof(priv_tx->control));
+ memcpy(priv_tx->data, skb->data, skb->len);
rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
- rt2x00_ring_index_inc(ring);
+ rt2x00queue_index_inc(queue, Q_INDEX);
return 0;
}
*/
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{
- struct data_ring *ring = rt2x00dev->rx;
- struct data_entry *entry;
- struct sk_buff *skb;
+ struct data_queue *queue = rt2x00dev->rx;
+ struct queue_entry *entry;
+ struct queue_entry_priv_pci_rx *priv_rx;
struct ieee80211_hdr *hdr;
- struct skb_desc *skbdesc;
- struct rxdata_entry_desc desc;
+ struct skb_frame_desc *skbdesc;
+ struct rxdone_entry_desc rxdesc;
int header_size;
- __le32 *rxd;
int align;
u32 word;
while (1) {
- entry = rt2x00_get_data_entry(ring);
- rxd = entry->priv;
- rt2x00_desc_read(rxd, 0, &word);
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ priv_rx = entry->priv_data;
+ rt2x00_desc_read(priv_rx->desc, 0, &word);
if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
break;
- memset(&desc, 0, sizeof(desc));
- rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+ memset(&rxdesc, 0, sizeof(rxdesc));
+ rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
- hdr = (struct ieee80211_hdr *)entry->data_addr;
+ hdr = (struct ieee80211_hdr *)priv_rx->data;
header_size =
ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
* Allocate the sk_buffer, initialize it and copy
* all data into it.
*/
- skb = dev_alloc_skb(desc.size + align);
- if (!skb)
+ entry->skb = dev_alloc_skb(rxdesc.size + align);
+ if (!entry->skb)
return;
- skb_reserve(skb, align);
- memcpy(skb_put(skb, desc.size), entry->data_addr, desc.size);
+ skb_reserve(entry->skb, align);
+ memcpy(skb_put(entry->skb, rxdesc.size),
+ priv_rx->data, rxdesc.size);
/*
* Fill in skb descriptor
*/
- skbdesc = get_skb_desc(skb);
- skbdesc->desc_len = entry->ring->desc_size;
- skbdesc->data_len = skb->len;
- skbdesc->desc = entry->priv;
- skbdesc->data = skb->data;
- skbdesc->ring = ring;
+ skbdesc = get_skb_frame_desc(entry->skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+ skbdesc->data = entry->skb->data;
+ skbdesc->data_len = entry->skb->len;
+ skbdesc->desc = priv_rx->desc;
+ skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry;
/*
* Send the frame to rt2x00lib for further processing.
*/
- rt2x00lib_rxdone(entry, skb, &desc);
+ rt2x00lib_rxdone(entry, &rxdesc);
- if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+ if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
- rt2x00_desc_write(rxd, 0, word);
+ rt2x00_desc_write(priv_rx->desc, 0, word);
}
- rt2x00_ring_index_inc(ring);
+ rt2x00queue_index_inc(queue, Q_INDEX);
}
}
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
-void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry,
- const int tx_status, const int retry)
+void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
+ struct txdone_entry_desc *txdesc)
{
+ struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
u32 word;
- rt2x00lib_txdone(entry, tx_status, retry);
+ txdesc->control = &priv_tx->control;
+ rt2x00lib_txdone(entry, txdesc);
/*
* Make this entry available for reuse.
*/
entry->flags = 0;
- rt2x00_desc_read(entry->priv, 0, &word);
+ rt2x00_desc_read(priv_tx->desc, 0, &word);
rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
- rt2x00_desc_write(entry->priv, 0, word);
+ rt2x00_desc_write(priv_tx->desc, 0, word);
- rt2x00_ring_index_done_inc(entry->ring);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
/*
- * If the data ring was full before the txdone handler
+ * If the data queue was full before the txdone handler
* we must make sure the packet queue in the mac80211 stack
* is reenabled when the txdone handler has finished.
*/
- if (!rt2x00_ring_full(entry->ring))
- ieee80211_wake_queue(rt2x00dev->hw,
- entry->tx_status.control.queue);
+ if (!rt2x00queue_full(entry->queue))
+ ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue);
}
EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
/*
* Device initialization handlers.
*/
-#define priv_offset(__ring, __i) \
-({ \
- ring->data_addr + (i * ring->desc_size); \
+#define desc_size(__queue) \
+({ \
+ ((__queue)->limit * (__queue)->desc_size);\
+})
+
+#define data_size(__queue) \
+({ \
+ ((__queue)->limit * (__queue)->data_size);\
})
-#define data_addr_offset(__ring, __i) \
-({ \
- (__ring)->data_addr + \
- ((__ring)->stats.limit * (__ring)->desc_size) + \
- ((__i) * (__ring)->data_size); \
+#define dma_size(__queue) \
+({ \
+ data_size(__queue) + desc_size(__queue);\
})
-#define data_dma_offset(__ring, __i) \
-({ \
- (__ring)->data_dma + \
- ((__ring)->stats.limit * (__ring)->desc_size) + \
- ((__i) * (__ring)->data_size); \
+#define desc_offset(__queue, __base, __i) \
+({ \
+ (__base) + data_size(__queue) + \
+ ((__i) * (__queue)->desc_size); \
})
-static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring)
+#define data_offset(__queue, __base, __i) \
+({ \
+ (__base) + \
+ ((__i) * (__queue)->data_size); \
+})
+
+static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_queue *queue)
{
+ struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+ struct queue_entry_priv_pci_rx *priv_rx;
+ struct queue_entry_priv_pci_tx *priv_tx;
+ void *addr;
+ dma_addr_t dma;
+ void *desc_addr;
+ dma_addr_t desc_dma;
+ void *data_addr;
+ dma_addr_t data_dma;
unsigned int i;
/*
* Allocate DMA memory for descriptor and buffer.
*/
- ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev),
- rt2x00_get_ring_size(ring),
- &ring->data_dma);
- if (!ring->data_addr)
+ addr = pci_alloc_consistent(pci_dev, dma_size(queue), &dma);
+ if (!addr)
return -ENOMEM;
+ memset(addr, 0, dma_size(queue));
+
/*
- * Initialize all ring entries to contain valid
- * addresses.
+ * Initialize all queue entries to contain valid addresses.
*/
- for (i = 0; i < ring->stats.limit; i++) {
- ring->entry[i].priv = priv_offset(ring, i);
- ring->entry[i].data_addr = data_addr_offset(ring, i);
- ring->entry[i].data_dma = data_dma_offset(ring, i);
+ for (i = 0; i < queue->limit; i++) {
+ desc_addr = desc_offset(queue, addr, i);
+ desc_dma = desc_offset(queue, dma, i);
+ data_addr = data_offset(queue, addr, i);
+ data_dma = data_offset(queue, dma, i);
+
+ if (queue->qid == QID_RX) {
+ priv_rx = queue->entries[i].priv_data;
+ priv_rx->desc = desc_addr;
+ priv_rx->desc_dma = desc_dma;
+ priv_rx->data = data_addr;
+ priv_rx->data_dma = data_dma;
+ } else {
+ priv_tx = queue->entries[i].priv_data;
+ priv_tx->desc = desc_addr;
+ priv_tx->desc_dma = desc_dma;
+ priv_tx->data = data_addr;
+ priv_tx->data_dma = data_dma;
+ }
}
return 0;
}
-static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring)
+static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_queue *queue)
{
- if (ring->data_addr)
- pci_free_consistent(rt2x00dev_pci(rt2x00dev),
- rt2x00_get_ring_size(ring),
- ring->data_addr, ring->data_dma);
- ring->data_addr = NULL;
+ struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+ struct queue_entry_priv_pci_rx *priv_rx;
+ struct queue_entry_priv_pci_tx *priv_tx;
+ void *data_addr;
+ dma_addr_t data_dma;
+
+ if (queue->qid == QID_RX) {
+ priv_rx = queue->entries[0].priv_data;
+ data_addr = priv_rx->data;
+ data_dma = priv_rx->data_dma;
+
+ priv_rx->data = NULL;
+ } else {
+ priv_tx = queue->entries[0].priv_data;
+ data_addr = priv_tx->data;
+ data_dma = priv_tx->data_dma;
+
+ priv_tx->data = NULL;
+ }
+
+ if (data_addr)
+ pci_free_consistent(pci_dev, dma_size(queue),
+ data_addr, data_dma);
}
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
- struct data_ring *ring;
+ struct data_queue *queue;
int status;
/*
* Allocate DMA
*/
- ring_for_each(rt2x00dev, ring) {
- status = rt2x00pci_alloc_dma(rt2x00dev, ring);
+ queue_for_each(rt2x00dev, queue) {
+ status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue);
if (status)
goto exit;
}
void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
{
- struct data_ring *ring;
+ struct data_queue *queue;
/*
* Free irq line.
/*
* Free DMA
*/
- ring_for_each(rt2x00dev, ring)
- rt2x00pci_free_dma(rt2x00dev, ring);
+ queue_for_each(rt2x00dev, queue)
+ rt2x00pci_free_queue_dma(rt2x00dev, queue);
}
EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
kfree(rt2x00dev->eeprom);
rt2x00dev->eeprom = NULL;
- if (rt2x00dev->csr_addr) {
- iounmap(rt2x00dev->csr_addr);
- rt2x00dev->csr_addr = NULL;
+ if (rt2x00dev->csr.base) {
+ iounmap(rt2x00dev->csr.base);
+ rt2x00dev->csr.base = NULL;
}
}
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
- rt2x00dev->csr_addr = ioremap(pci_resource_start(pci_dev, 0),
+ rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0),
pci_resource_len(pci_dev, 0));
- if (!rt2x00dev->csr_addr)
+ if (!rt2x00dev->csr.base)
goto exit;
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
*/
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
-MODULE_DESCRIPTION("rt2x00 library");
+MODULE_DESCRIPTION("rt2x00 pci library");
MODULE_LICENSE("GPL");
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
const unsigned long offset,
u32 *value)
{
- *value = readl(rt2x00dev->csr_addr + offset);
+ *value = readl(rt2x00dev->csr.base + offset);
}
static inline void
const unsigned long offset,
void *value, const u16 length)
{
- memcpy_fromio(value, rt2x00dev->csr_addr + offset, length);
+ memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
}
static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned long offset,
u32 value)
{
- writel(value, rt2x00dev->csr_addr + offset);
+ writel(value, rt2x00dev->csr.base + offset);
}
static inline void
const unsigned long offset,
void *value, const u16 length)
{
- memcpy_toio(rt2x00dev->csr_addr + offset, value, length);
+ memcpy_toio(rt2x00dev->csr.base + offset, value, length);
}
/*
- * Beacon handlers.
- */
-int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control);
-
-/*
* TX data handlers.
*/
int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring, struct sk_buff *skb,
+ struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_tx_control *control);
-/*
- * RX/TX data handlers.
+/**
+ * struct queue_entry_priv_pci_rx: Per RX entry PCI specific information
+ *
+ * @desc: Pointer to device descriptor.
+ * @data: Pointer to device's entry memory.
+ * @dma: DMA pointer to &data.
+ */
+struct queue_entry_priv_pci_rx {
+ __le32 *desc;
+ dma_addr_t desc_dma;
+
+ void *data;
+ dma_addr_t data_dma;
+};
+
+/**
+ * struct queue_entry_priv_pci_tx: Per TX entry PCI specific information
+ *
+ * @desc: Pointer to device descriptor
+ * @data: Pointer to device's entry memory.
+ * @dma: DMA pointer to &data.
+ * @control: mac80211 control structure used to transmit data.
+ */
+struct queue_entry_priv_pci_tx {
+ __le32 *desc;
+ dma_addr_t desc_dma;
+
+ void *data;
+ dma_addr_t data_dma;
+
+ struct ieee80211_tx_control control;
+};
+
+/**
+ * rt2x00pci_rxdone - Handle RX done events
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
*/
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
-void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry,
- const int tx_status, const int retry);
+
+/**
+ * rt2x00pci_txdone - Handle TX done events
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @entry: Entry which has completed the transmission of a frame.
+ * @desc: TX done descriptor
+ */
+void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
+ struct txdone_entry_desc *desc);
/*
* Device initialization handlers.
--- /dev/null
+/*
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ 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.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 queue specific routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
+ const unsigned int queue)
+{
+ int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+
+ if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
+ return &rt2x00dev->tx[queue];
+
+ if (!rt2x00dev->bcn)
+ return NULL;
+
+ if (queue == RT2X00_BCN_QUEUE_BEACON)
+ return &rt2x00dev->bcn[0];
+ else if (queue == RT2X00_BCN_QUEUE_ATIM && atim)
+ return &rt2x00dev->bcn[1];
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_get_queue);
+
+struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
+ enum queue_index index)
+{
+ struct queue_entry *entry;
+ unsigned long irqflags;
+
+ if (unlikely(index >= Q_INDEX_MAX)) {
+ ERROR(queue->rt2x00dev,
+ "Entry requested from invalid index type (%d)\n", index);
+ return NULL;
+ }
+
+ spin_lock_irqsave(&queue->lock, irqflags);
+
+ entry = &queue->entries[queue->index[index]];
+
+ spin_unlock_irqrestore(&queue->lock, irqflags);
+
+ return entry;
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_get_entry);
+
+void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
+{
+ unsigned long irqflags;
+
+ if (unlikely(index >= Q_INDEX_MAX)) {
+ ERROR(queue->rt2x00dev,
+ "Index change on invalid index type (%d)\n", index);
+ return;
+ }
+
+ spin_lock_irqsave(&queue->lock, irqflags);
+
+ queue->index[index]++;
+ if (queue->index[index] >= queue->limit)
+ queue->index[index] = 0;
+
+ if (index == Q_INDEX) {
+ queue->length++;
+ } else if (index == Q_INDEX_DONE) {
+ queue->length--;
+ queue->count ++;
+ }
+
+ spin_unlock_irqrestore(&queue->lock, irqflags);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_index_inc);
+
+static void rt2x00queue_reset(struct data_queue *queue)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&queue->lock, irqflags);
+
+ queue->count = 0;
+ queue->length = 0;
+ memset(queue->index, 0, sizeof(queue->index));
+
+ spin_unlock_irqrestore(&queue->lock, irqflags);
+}
+
+void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue = rt2x00dev->rx;
+ unsigned int i;
+
+ rt2x00queue_reset(queue);
+
+ if (!rt2x00dev->ops->lib->init_rxentry)
+ return;
+
+ for (i = 0; i < queue->limit; i++)
+ rt2x00dev->ops->lib->init_rxentry(rt2x00dev,
+ &queue->entries[i]);
+}
+
+void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ unsigned int i;
+
+ txall_queue_for_each(rt2x00dev, queue) {
+ rt2x00queue_reset(queue);
+
+ if (!rt2x00dev->ops->lib->init_txentry)
+ continue;
+
+ for (i = 0; i < queue->limit; i++)
+ rt2x00dev->ops->lib->init_txentry(rt2x00dev,
+ &queue->entries[i]);
+ }
+}
+
+static int rt2x00queue_alloc_entries(struct data_queue *queue,
+ const struct data_queue_desc *qdesc)
+{
+ struct queue_entry *entries;
+ unsigned int entry_size;
+ unsigned int i;
+
+ rt2x00queue_reset(queue);
+
+ queue->limit = qdesc->entry_num;
+ queue->data_size = qdesc->data_size;
+ queue->desc_size = qdesc->desc_size;
+
+ /*
+ * Allocate all queue entries.
+ */
+ entry_size = sizeof(*entries) + qdesc->priv_size;
+ entries = kzalloc(queue->limit * entry_size, GFP_KERNEL);
+ if (!entries)
+ return -ENOMEM;
+
+#define QUEUE_ENTRY_PRIV_OFFSET(__base, __index, __limit, __esize, __psize) \
+ ( ((char *)(__base)) + ((__limit) * (__esize)) + \
+ ((__index) * (__psize)) )
+
+ for (i = 0; i < queue->limit; i++) {
+ entries[i].flags = 0;
+ entries[i].queue = queue;
+ entries[i].skb = NULL;
+ entries[i].entry_idx = i;
+ entries[i].priv_data =
+ QUEUE_ENTRY_PRIV_OFFSET(entries, i, queue->limit,
+ sizeof(*entries), qdesc->priv_size);
+ }
+
+#undef QUEUE_ENTRY_PRIV_OFFSET
+
+ queue->entries = entries;
+
+ return 0;
+}
+
+int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ int status;
+
+
+ status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
+ if (status)
+ goto exit;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ status = rt2x00queue_alloc_entries(queue, rt2x00dev->ops->tx);
+ if (status)
+ goto exit;
+ }
+
+ status = rt2x00queue_alloc_entries(rt2x00dev->bcn, rt2x00dev->ops->bcn);
+ if (status)
+ goto exit;
+
+ if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
+ return 0;
+
+ status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1],
+ rt2x00dev->ops->atim);
+ if (status)
+ goto exit;
+
+ return 0;
+
+exit:
+ ERROR(rt2x00dev, "Queue entries allocation failed.\n");
+
+ rt2x00queue_uninitialize(rt2x00dev);
+
+ return status;
+}
+
+void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ queue_for_each(rt2x00dev, queue) {
+ kfree(queue->entries);
+ queue->entries = NULL;
+ }
+}
+
+static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
+ struct data_queue *queue, enum data_queue_qid qid)
+{
+ spin_lock_init(&queue->lock);
+
+ queue->rt2x00dev = rt2x00dev;
+ queue->qid = qid;
+ queue->aifs = 2;
+ queue->cw_min = 5;
+ queue->cw_max = 10;
+}
+
+int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ enum data_queue_qid qid;
+ unsigned int req_atim =
+ !!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+
+ /*
+ * We need the following queues:
+ * RX: 1
+ * TX: hw->queues
+ * Beacon: 1
+ * Atim: 1 (if required)
+ */
+ rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim;
+
+ queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
+ if (!queue) {
+ ERROR(rt2x00dev, "Queue allocation failed.\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Initialize pointers
+ */
+ rt2x00dev->rx = queue;
+ rt2x00dev->tx = &queue[1];
+ rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues];
+
+ /*
+ * Initialize queue parameters.
+ * RX: qid = QID_RX
+ * TX: qid = QID_AC_BE + index
+ * TX: cw_min: 2^5 = 32.
+ * TX: cw_max: 2^10 = 1024.
+ * BCN & Atim: qid = QID_MGMT
+ */
+ rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX);
+
+ qid = QID_AC_BE;
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_init(rt2x00dev, queue, qid++);
+
+ rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[0], QID_MGMT);
+ if (req_atim)
+ rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[1], QID_MGMT);
+
+ return 0;
+}
+
+void rt2x00queue_free(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rx);
+ rt2x00dev->rx = NULL;
+ rt2x00dev->tx = NULL;
+ rt2x00dev->bcn = NULL;
+}
--- /dev/null
+/*
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ 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.
+ */
+
+/*
+ Module: rt2x00
+ Abstract: rt2x00 queue datastructures and routines
+ */
+
+#ifndef RT2X00QUEUE_H
+#define RT2X00QUEUE_H
+
+#include <linux/prefetch.h>
+
+/**
+ * DOC: Entrie frame size
+ *
+ * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
+ * for USB devices this restriction does not apply, but the value of
+ * 2432 makes sense since it is big enough to contain the maximum fragment
+ * size according to the ieee802.11 specs.
+ */
+#define DATA_FRAME_SIZE 2432
+#define MGMT_FRAME_SIZE 256
+
+/**
+ * DOC: Number of entries per queue
+ *
+ * After research it was concluded that 12 entries in a RX and TX
+ * queue would be sufficient. Although this is almost one third of
+ * the amount the legacy driver allocated, the queues aren't getting
+ * filled to the maximum even when working with the maximum rate.
+ */
+#define RX_ENTRIES 12
+#define TX_ENTRIES 12
+#define BEACON_ENTRIES 1
+#define ATIM_ENTRIES 1
+
+/**
+ * enum data_queue_qid: Queue identification
+ */
+enum data_queue_qid {
+ QID_AC_BE = 0,
+ QID_AC_BK = 1,
+ QID_AC_VI = 2,
+ QID_AC_VO = 3,
+ QID_HCCA = 4,
+ QID_MGMT = 13,
+ QID_RX = 14,
+ QID_OTHER = 15,
+};
+
+/**
+ * enum rt2x00_bcn_queue: Beacon queue index
+ *
+ * Start counting with a high offset, this because this enumeration
+ * supplements &enum ieee80211_tx_queue and we should prevent value
+ * conflicts.
+ *
+ * @RT2X00_BCN_QUEUE_BEACON: Beacon queue
+ * @RT2X00_BCN_QUEUE_ATIM: Atim queue (sends frame after beacon)
+ */
+enum rt2x00_bcn_queue {
+ RT2X00_BCN_QUEUE_BEACON = 100,
+ RT2X00_BCN_QUEUE_ATIM = 101,
+};
+
+/**
+ * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
+ *
+ * @FRAME_DESC_DRIVER_GENERATED: Frame was generated inside driver
+ * and should not be reported back to mac80211 during txdone.
+ */
+enum skb_frame_desc_flags {
+ FRAME_DESC_DRIVER_GENERATED = 1 << 0,
+};
+
+/**
+ * struct skb_frame_desc: Descriptor information for the skb buffer
+ *
+ * This structure is placed over the skb->cb array, this means that
+ * this structure should not exceed the size of that array (48 bytes).
+ *
+ * @flags: Frame flags, see &enum skb_frame_desc_flags.
+ * @frame_type: Frame type, see &enum rt2x00_dump_type.
+ * @data: Pointer to data part of frame (Start of ieee80211 header).
+ * @desc: Pointer to descriptor part of the frame.
+ * Note that this pointer could point to something outside
+ * of the scope of the skb->data pointer.
+ * @data_len: Length of the frame data.
+ * @desc_len: Length of the frame descriptor.
+
+ * @entry: The entry to which this sk buffer belongs.
+ */
+struct skb_frame_desc {
+ unsigned int flags;
+
+ unsigned int frame_type;
+
+ void *data;
+ void *desc;
+
+ unsigned int data_len;
+ unsigned int desc_len;
+
+ struct queue_entry *entry;
+};
+
+static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb)
+{
+ BUILD_BUG_ON(sizeof(struct skb_frame_desc) > sizeof(skb->cb));
+ return (struct skb_frame_desc *)&skb->cb[0];
+}
+
+/**
+ * struct rxdone_entry_desc: RX Entry descriptor
+ *
+ * Summary of information that has been read from the RX frame descriptor.
+ *
+ * @signal: Signal of the received frame.
+ * @signal_plcp: Does the signal field contain the plcp value,
+ * or does it contain the bitrate itself.
+ * @rssi: RSSI of the received frame.
+ * @ofdm: Was frame send with an OFDM rate.
+ * @size: Data size of the received frame.
+ * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags).
+ * @my_bss: Does this frame originate from device's BSS.
+ */
+struct rxdone_entry_desc {
+ int signal;
+ int signal_plcp;
+ int rssi;
+ int ofdm;
+ int size;
+ int flags;
+ int my_bss;
+};
+
+/**
+ * struct txdone_entry_desc: TX done entry descriptor
+ *
+ * Summary of information that has been read from the TX frame descriptor
+ * after the device is done with transmission.
+ *
+ * @control: Control structure which was used to transmit the frame.
+ * @status: TX status (See &enum tx_status).
+ * @retry: Retry count.
+ */
+struct txdone_entry_desc {
+ struct ieee80211_tx_control *control;
+ int status;
+ int retry;
+};
+
+/**
+ * enum txentry_desc_flags: Status flags for TX entry descriptor
+ *
+ * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
+ * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate.
+ * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
+ * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
+ * @ENTRY_TXD_BURST: This frame belongs to the same burst event.
+ * @ENTRY_TXD_ACK: An ACK is required for this frame.
+ */
+enum txentry_desc_flags {
+ ENTRY_TXD_RTS_FRAME,
+ ENTRY_TXD_OFDM_RATE,
+ ENTRY_TXD_MORE_FRAG,
+ ENTRY_TXD_REQ_TIMESTAMP,
+ ENTRY_TXD_BURST,
+ ENTRY_TXD_ACK,
+};
+
+/**
+ * struct txentry_desc: TX Entry descriptor
+ *
+ * Summary of information for the frame descriptor before sending a TX frame.
+ *
+ * @flags: Descriptor flags (See &enum queue_entry_flags).
+ * @queue: Queue identification (See &enum data_queue_qid).
+ * @length_high: PLCP length high word.
+ * @length_low: PLCP length low word.
+ * @signal: PLCP signal.
+ * @service: PLCP service.
+ * @aifs: AIFS value.
+ * @ifs: IFS value.
+ * @cw_min: cwmin value.
+ * @cw_max: cwmax value.
+ */
+struct txentry_desc {
+ unsigned long flags;
+
+ enum data_queue_qid queue;
+
+ u16 length_high;
+ u16 length_low;
+ u16 signal;
+ u16 service;
+
+ int aifs;
+ int ifs;
+ int cw_min;
+ int cw_max;
+};
+
+/**
+ * enum queue_entry_flags: Status flags for queue entry
+ *
+ * @ENTRY_BCN_ASSIGNED: This entry has been assigned to an interface.
+ * As long as this bit is set, this entry may only be touched
+ * through the interface structure.
+ * @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data
+ * transfer (either TX or RX depending on the queue). The entry should
+ * only be touched after the device has signaled it is done with it.
+ * @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data
+ * encryption or decryption. The entry should only be touched after
+ * the device has signaled it is done with it.
+ */
+
+enum queue_entry_flags {
+ ENTRY_BCN_ASSIGNED,
+ ENTRY_OWNER_DEVICE_DATA,
+ ENTRY_OWNER_DEVICE_CRYPTO,
+};
+
+/**
+ * struct queue_entry: Entry inside the &struct data_queue
+ *
+ * @flags: Entry flags, see &enum queue_entry_flags.
+ * @queue: The data queue (&struct data_queue) to which this entry belongs.
+ * @skb: The buffer which is currently being transmitted (for TX queue),
+ * or used to directly recieve data in (for RX queue).
+ * @entry_idx: The entry index number.
+ * @priv_data: Private data belonging to this queue entry. The pointer
+ * points to data specific to a particular driver and queue type.
+ */
+struct queue_entry {
+ unsigned long flags;
+
+ struct data_queue *queue;
+
+ struct sk_buff *skb;
+
+ unsigned int entry_idx;
+
+ void *priv_data;
+};
+
+/**
+ * enum queue_index: Queue index type
+ *
+ * @Q_INDEX: Index pointer to the current entry in the queue, if this entry is
+ * owned by the hardware then the queue is considered to be full.
+ * @Q_INDEX_DONE: Index pointer to the next entry which will be completed by
+ * the hardware and for which we need to run the txdone handler. If this
+ * entry is not owned by the hardware the queue is considered to be empty.
+ * @Q_INDEX_CRYPTO: Index pointer to the next entry which encryption/decription
+ * will be completed by the hardware next.
+ * @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size
+ * of the index array.
+ */
+enum queue_index {
+ Q_INDEX,
+ Q_INDEX_DONE,
+ Q_INDEX_CRYPTO,
+ Q_INDEX_MAX,
+};
+
+/**
+ * struct data_queue: Data queue
+ *
+ * @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to.
+ * @entries: Base address of the &struct queue_entry which are
+ * part of this queue.
+ * @qid: The queue identification, see &enum data_queue_qid.
+ * @lock: Spinlock to protect index handling. Whenever @index, @index_done or
+ * @index_crypt needs to be changed this lock should be grabbed to prevent
+ * index corruption due to concurrency.
+ * @count: Number of frames handled in the queue.
+ * @limit: Maximum number of entries in the queue.
+ * @length: Number of frames in queue.
+ * @index: Index pointers to entry positions in the queue,
+ * use &enum queue_index to get a specific index field.
+ * @aifs: The aifs value for outgoing frames (field ignored in RX queue).
+ * @cw_min: The cw min value for outgoing frames (field ignored in RX queue).
+ * @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
+ * @data_size: Maximum data size for the frames in this queue.
+ * @desc_size: Hardware descriptor size for the data in this queue.
+ */
+struct data_queue {
+ struct rt2x00_dev *rt2x00dev;
+ struct queue_entry *entries;
+
+ enum data_queue_qid qid;
+
+ spinlock_t lock;
+ unsigned int count;
+ unsigned short limit;
+ unsigned short length;
+ unsigned short index[Q_INDEX_MAX];
+
+ unsigned short aifs;
+ unsigned short cw_min;
+ unsigned short cw_max;
+
+ unsigned short data_size;
+ unsigned short desc_size;
+};
+
+/**
+ * struct data_queue_desc: Data queue description
+ *
+ * The information in this structure is used by drivers
+ * to inform rt2x00lib about the creation of the data queue.
+ *
+ * @entry_num: Maximum number of entries for a queue.
+ * @data_size: Maximum data size for the frames in this queue.
+ * @desc_size: Hardware descriptor size for the data in this queue.
+ * @priv_size: Size of per-queue_entry private data.
+ */
+struct data_queue_desc {
+ unsigned short entry_num;
+ unsigned short data_size;
+ unsigned short desc_size;
+ unsigned short priv_size;
+};
+
+/**
+ * queue_end - Return pointer to the last queue (HELPER MACRO).
+ * @__dev: Pointer to &struct rt2x00_dev
+ *
+ * Using the base rx pointer and the maximum number of available queues,
+ * this macro will return the address of 1 position beyond the end of the
+ * queues array.
+ */
+#define queue_end(__dev) \
+ &(__dev)->rx[(__dev)->data_queues]
+
+/**
+ * tx_queue_end - Return pointer to the last TX queue (HELPER MACRO).
+ * @__dev: Pointer to &struct rt2x00_dev
+ *
+ * Using the base tx pointer and the maximum number of available TX
+ * queues, this macro will return the address of 1 position beyond
+ * the end of the TX queue array.
+ */
+#define tx_queue_end(__dev) \
+ &(__dev)->tx[(__dev)->hw->queues]
+
+/**
+ * queue_loop - Loop through the queues within a specific range (HELPER MACRO).
+ * @__entry: Pointer where the current queue entry will be stored in.
+ * @__start: Start queue pointer.
+ * @__end: End queue pointer.
+ *
+ * This macro will loop through all queues between &__start and &__end.
+ */
+#define queue_loop(__entry, __start, __end) \
+ for ((__entry) = (__start); \
+ prefetch(&(__entry)[1]), (__entry) != (__end); \
+ (__entry) = &(__entry)[1])
+
+/**
+ * queue_for_each - Loop through all queues
+ * @__dev: Pointer to &struct rt2x00_dev
+ * @__entry: Pointer where the current queue entry will be stored in.
+ *
+ * This macro will loop through all available queues.
+ */
+#define queue_for_each(__dev, __entry) \
+ queue_loop(__entry, (__dev)->rx, queue_end(__dev))
+
+/**
+ * tx_queue_for_each - Loop through the TX queues
+ * @__dev: Pointer to &struct rt2x00_dev
+ * @__entry: Pointer where the current queue entry will be stored in.
+ *
+ * This macro will loop through all TX related queues excluding
+ * the Beacon and Atim queues.
+ */
+#define tx_queue_for_each(__dev, __entry) \
+ queue_loop(__entry, (__dev)->tx, tx_queue_end(__dev))
+
+/**
+ * txall_queue_for_each - Loop through all TX related queues
+ * @__dev: Pointer to &struct rt2x00_dev
+ * @__entry: Pointer where the current queue entry will be stored in.
+ *
+ * This macro will loop through all TX related queues including
+ * the Beacon and Atim queues.
+ */
+#define txall_queue_for_each(__dev, __entry) \
+ queue_loop(__entry, (__dev)->tx, queue_end(__dev))
+
+/**
+ * rt2x00queue_empty - Check if the queue is empty.
+ * @queue: Queue to check if empty.
+ */
+static inline int rt2x00queue_empty(struct data_queue *queue)
+{
+ return queue->length == 0;
+}
+
+/**
+ * rt2x00queue_full - Check if the queue is full.
+ * @queue: Queue to check if full.
+ */
+static inline int rt2x00queue_full(struct data_queue *queue)
+{
+ return queue->length == queue->limit;
+}
+
+/**
+ * rt2x00queue_free - Check the number of available entries in queue.
+ * @queue: Queue to check.
+ */
+static inline int rt2x00queue_available(struct data_queue *queue)
+{
+ return queue->limit - queue->length;
+}
+
+/**
+ * rt2x00_desc_read - Read a word from the hardware descriptor.
+ * @desc: Base descriptor address
+ * @word: Word index from where the descriptor should be read.
+ * @value: Address where the descriptor value should be written into.
+ */
+static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value)
+{
+ *value = le32_to_cpu(desc[word]);
+}
+
+/**
+ * rt2x00_desc_write - wrote a word to the hardware descriptor.
+ * @desc: Base descriptor address
+ * @word: Word index from where the descriptor should be written.
+ * @value: Value that should be written into the descriptor.
+ */
+static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value)
+{
+ desc[word] = cpu_to_le32(value);
+}
+
+#endif /* RT2X00QUEUE_H */
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
/*
* TX result flags.
*/
-enum TX_STATUS {
+enum tx_status {
TX_SUCCESS = 0,
TX_SUCCESS_RETRY = 1,
TX_FAIL_RETRY = 2,
return (reg & field.bit_mask) >> field.bit_offset;
}
-/*
- * Device specific rate value.
- * We will have to create the device specific rate value
- * passed to the ieee80211 kernel. We need to make it a consist of
- * multiple fields because we want to store more then 1 device specific
- * values inside the value.
- * 1 - rate, stored as 100 kbit/s.
- * 2 - preamble, short_preamble enabled flag.
- * 3 - MASK_RATE, which rates are enabled in this mode, this mask
- * corresponds with the TX register format for the current device.
- * 4 - plcp, 802.11b rates are device specific,
- * 802.11g rates are set according to the ieee802.11a-1999 p.14.
- * The bit to enable preamble is set in a seperate define.
- */
-#define DEV_RATE FIELD32(0x000007ff)
-#define DEV_PREAMBLE FIELD32(0x00000800)
-#define DEV_RATEMASK FIELD32(0x00fff000)
-#define DEV_PLCP FIELD32(0xff000000)
-
-/*
- * Bitfields
- */
-#define DEV_RATEBIT_1MB ( 1 << 0 )
-#define DEV_RATEBIT_2MB ( 1 << 1 )
-#define DEV_RATEBIT_5_5MB ( 1 << 2 )
-#define DEV_RATEBIT_11MB ( 1 << 3 )
-#define DEV_RATEBIT_6MB ( 1 << 4 )
-#define DEV_RATEBIT_9MB ( 1 << 5 )
-#define DEV_RATEBIT_12MB ( 1 << 6 )
-#define DEV_RATEBIT_18MB ( 1 << 7 )
-#define DEV_RATEBIT_24MB ( 1 << 8 )
-#define DEV_RATEBIT_36MB ( 1 << 9 )
-#define DEV_RATEBIT_48MB ( 1 << 10 )
-#define DEV_RATEBIT_54MB ( 1 << 11 )
-
-/*
- * Bitmasks for DEV_RATEMASK
- */
-#define DEV_RATEMASK_1MB ( (DEV_RATEBIT_1MB << 1) -1 )
-#define DEV_RATEMASK_2MB ( (DEV_RATEBIT_2MB << 1) -1 )
-#define DEV_RATEMASK_5_5MB ( (DEV_RATEBIT_5_5MB << 1) -1 )
-#define DEV_RATEMASK_11MB ( (DEV_RATEBIT_11MB << 1) -1 )
-#define DEV_RATEMASK_6MB ( (DEV_RATEBIT_6MB << 1) -1 )
-#define DEV_RATEMASK_9MB ( (DEV_RATEBIT_9MB << 1) -1 )
-#define DEV_RATEMASK_12MB ( (DEV_RATEBIT_12MB << 1) -1 )
-#define DEV_RATEMASK_18MB ( (DEV_RATEBIT_18MB << 1) -1 )
-#define DEV_RATEMASK_24MB ( (DEV_RATEBIT_24MB << 1) -1 )
-#define DEV_RATEMASK_36MB ( (DEV_RATEBIT_36MB << 1) -1 )
-#define DEV_RATEMASK_48MB ( (DEV_RATEBIT_48MB << 1) -1 )
-#define DEV_RATEMASK_54MB ( (DEV_RATEBIT_54MB << 1) -1 )
-
-/*
- * Bitmask groups of bitrates
- */
-#define DEV_BASIC_RATEMASK \
- ( DEV_RATEMASK_11MB | \
- DEV_RATEBIT_6MB | DEV_RATEBIT_12MB | DEV_RATEBIT_24MB )
-
-#define DEV_CCK_RATEMASK ( DEV_RATEMASK_11MB )
-#define DEV_OFDM_RATEMASK ( DEV_RATEMASK_54MB & ~DEV_CCK_RATEMASK )
-
-/*
- * Macro's to set and get specific fields from the device specific val and val2
- * fields inside the ieee80211_rate entry.
- */
-#define DEVICE_SET_RATE_FIELD(__value, __mask) \
- (int)( ((__value) << DEV_##__mask.bit_offset) & DEV_##__mask.bit_mask )
-
-#define DEVICE_GET_RATE_FIELD(__value, __mask) \
- (int)( ((__value) & DEV_##__mask.bit_mask) >> DEV_##__mask.bit_offset )
-
#endif /* RT2X00REG_H */
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
+++ /dev/null
-/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
- <http://rt2x00.serialmonkey.com>
-
- 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.
- */
-
-/*
- Module: rt2x00
- Abstract: rt2x00 ring datastructures and routines
- */
-
-#ifndef RT2X00RING_H
-#define RT2X00RING_H
-
-/*
- * skb_desc
- * Descriptor information for the skb buffer
- */
-struct skb_desc {
- unsigned int frame_type;
-
- unsigned int desc_len;
- unsigned int data_len;
-
- void *desc;
- void *data;
-
- struct data_ring *ring;
- struct data_entry *entry;
-};
-
-static inline struct skb_desc* get_skb_desc(struct sk_buff *skb)
-{
- return (struct skb_desc*)&skb->cb[0];
-}
-
-/*
- * rxdata_entry_desc
- * Summary of information that has been read from the
- * RX frame descriptor.
- */
-struct rxdata_entry_desc {
- int signal;
- int rssi;
- int ofdm;
- int size;
- int flags;
- int my_bss;
-};
-
-/*
- * txdata_entry_desc
- * Summary of information that should be written into the
- * descriptor for sending a TX frame.
- */
-struct txdata_entry_desc {
- unsigned long flags;
-#define ENTRY_TXDONE 1
-#define ENTRY_TXD_RTS_FRAME 2
-#define ENTRY_TXD_OFDM_RATE 3
-#define ENTRY_TXD_MORE_FRAG 4
-#define ENTRY_TXD_REQ_TIMESTAMP 5
-#define ENTRY_TXD_BURST 6
-#define ENTRY_TXD_ACK 7
-
-/*
- * Queue ID. ID's 0-4 are data TX rings
- */
- int queue;
-#define QUEUE_MGMT 13
-#define QUEUE_RX 14
-#define QUEUE_OTHER 15
-
- /*
- * PLCP values.
- */
- u16 length_high;
- u16 length_low;
- u16 signal;
- u16 service;
-
- /*
- * Timing information
- */
- int aifs;
- int ifs;
- int cw_min;
- int cw_max;
-};
-
-/*
- * data_entry
- * The data ring is a list of data entries.
- * Each entry holds a reference to the descriptor
- * and the data buffer. For TX rings the reference to the
- * sk_buff of the packet being transmitted is also stored here.
- */
-struct data_entry {
- /*
- * Status flags
- */
- unsigned long flags;
-#define ENTRY_OWNER_NIC 1
-
- /*
- * Ring we belong to.
- */
- struct data_ring *ring;
-
- /*
- * sk_buff for the packet which is being transmitted
- * in this entry (Only used with TX related rings).
- */
- struct sk_buff *skb;
-
- /*
- * Store a ieee80211_tx_status structure in each
- * ring entry, this will optimize the txdone
- * handler.
- */
- struct ieee80211_tx_status tx_status;
-
- /*
- * private pointer specific to driver.
- */
- void *priv;
-
- /*
- * Data address for this entry.
- */
- void *data_addr;
- dma_addr_t data_dma;
-
- /*
- * Entry identification number (index).
- */
- unsigned int entry_idx;
-};
-
-/*
- * data_ring
- * Data rings are used by the device to send and receive packets.
- * The data_addr is the base address of the data memory.
- * To determine at which point in the ring we are,
- * have to use the rt2x00_ring_index_*() functions.
- */
-struct data_ring {
- /*
- * Pointer to main rt2x00dev structure where this
- * ring belongs to.
- */
- struct rt2x00_dev *rt2x00dev;
-
- /*
- * Base address for the device specific data entries.
- */
- struct data_entry *entry;
-
- /*
- * TX queue statistic info.
- */
- struct ieee80211_tx_queue_stats_data stats;
-
- /*
- * TX Queue parameters.
- */
- struct ieee80211_tx_queue_params tx_params;
-
- /*
- * Base address for data ring.
- */
- dma_addr_t data_dma;
- void *data_addr;
-
- /*
- * Queue identification number:
- * RX: 0
- * TX: IEEE80211_TX_*
- */
- unsigned int queue_idx;
-
- /*
- * Index variables.
- */
- u16 index;
- u16 index_done;
-
- /*
- * Size of packet and descriptor in bytes.
- */
- u16 data_size;
- u16 desc_size;
-};
-
-/*
- * Handlers to determine the address of the current device specific
- * data entry, where either index or index_done points to.
- */
-static inline struct data_entry *rt2x00_get_data_entry(struct data_ring *ring)
-{
- return &ring->entry[ring->index];
-}
-
-static inline struct data_entry *rt2x00_get_data_entry_done(struct data_ring
- *ring)
-{
- return &ring->entry[ring->index_done];
-}
-
-/*
- * Total ring memory
- */
-static inline int rt2x00_get_ring_size(struct data_ring *ring)
-{
- return ring->stats.limit * (ring->desc_size + ring->data_size);
-}
-
-/*
- * Ring index manipulation functions.
- */
-static inline void rt2x00_ring_index_inc(struct data_ring *ring)
-{
- ring->index++;
- if (ring->index >= ring->stats.limit)
- ring->index = 0;
- ring->stats.len++;
-}
-
-static inline void rt2x00_ring_index_done_inc(struct data_ring *ring)
-{
- ring->index_done++;
- if (ring->index_done >= ring->stats.limit)
- ring->index_done = 0;
- ring->stats.len--;
- ring->stats.count++;
-}
-
-static inline void rt2x00_ring_index_clear(struct data_ring *ring)
-{
- ring->index = 0;
- ring->index_done = 0;
- ring->stats.len = 0;
- ring->stats.count = 0;
-}
-
-static inline int rt2x00_ring_empty(struct data_ring *ring)
-{
- return ring->stats.len == 0;
-}
-
-static inline int rt2x00_ring_full(struct data_ring *ring)
-{
- return ring->stats.len == ring->stats.limit;
-}
-
-static inline int rt2x00_ring_free(struct data_ring *ring)
-{
- return ring->stats.limit - ring->stats.len;
-}
-
-/*
- * TX/RX Descriptor access functions.
- */
-static inline void rt2x00_desc_read(__le32 *desc,
- const u8 word, u32 *value)
-{
- *value = le32_to_cpu(desc[word]);
-}
-
-static inline void rt2x00_desc_write(__le32 *desc,
- const u8 word, const u32 value)
-{
- desc[word] = cpu_to_le32(value);
-}
-
-#endif /* RT2X00RING_H */
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
void *buffer, const u16 buffer_length,
const int timeout)
{
- struct usb_device *usb_dev =
- interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
int status;
unsigned int i;
unsigned int pipe =
/*
* Check for Cache availability.
*/
- if (unlikely(!rt2x00dev->csr_cache || buffer_length > CSR_CACHE_SIZE)) {
+ if (unlikely(!rt2x00dev->csr.cache || buffer_length > CSR_CACHE_SIZE)) {
ERROR(rt2x00dev, "CSR cache not available.\n");
return -ENOMEM;
}
if (requesttype == USB_VENDOR_REQUEST_OUT)
- memcpy(rt2x00dev->csr_cache, buffer, buffer_length);
+ memcpy(rt2x00dev->csr.cache, buffer, buffer_length);
status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype,
- offset, 0, rt2x00dev->csr_cache,
+ offset, 0, rt2x00dev->csr.cache,
buffer_length, timeout);
if (!status && requesttype == USB_VENDOR_REQUEST_IN)
- memcpy(buffer, rt2x00dev->csr_cache, buffer_length);
+ memcpy(buffer, rt2x00dev->csr.cache, buffer_length);
return status;
}
*/
static void rt2x00usb_interrupt_txdone(struct urb *urb)
{
- struct data_entry *entry = (struct data_entry *)urb->context;
- struct data_ring *ring = entry->ring;
- struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+ struct queue_entry *entry = (struct queue_entry *)urb->context;
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data;
+ struct txdone_entry_desc txdesc;
__le32 *txd = (__le32 *)entry->skb->data;
u32 word;
- int tx_status;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
- !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+ !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
rt2x00_desc_read(txd, 0, &word);
/*
* Remove the descriptor data from the buffer.
*/
- skb_pull(entry->skb, ring->desc_size);
+ skb_pull(entry->skb, entry->queue->desc_size);
/*
* Obtain the status about this packet.
*/
- tx_status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY;
+ txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY;
+ txdesc.retry = 0;
+ txdesc.control = &priv_tx->control;
- rt2x00lib_txdone(entry, tx_status, 0);
+ rt2x00lib_txdone(entry, &txdesc);
/*
* Make this entry available for reuse.
*/
entry->flags = 0;
- rt2x00_ring_index_done_inc(entry->ring);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
/*
- * If the data ring was full before the txdone handler
+ * If the data queue was full before the txdone handler
* we must make sure the packet queue in the mac80211 stack
* is reenabled when the txdone handler has finished.
*/
- if (!rt2x00_ring_full(ring))
- ieee80211_wake_queue(rt2x00dev->hw,
- entry->tx_status.control.queue);
+ if (!rt2x00queue_full(entry->queue))
+ ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue);
}
int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring, struct sk_buff *skb,
+ struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_tx_control *control)
{
- struct usb_device *usb_dev =
- interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
- struct data_entry *entry = rt2x00_get_data_entry(ring);
- struct skb_desc *desc;
+ struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
+ struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data;
+ struct skb_frame_desc *skbdesc;
u32 length;
- if (rt2x00_ring_full(ring))
+ if (rt2x00queue_full(queue))
return -EINVAL;
- if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) {
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
ERROR(rt2x00dev,
"Arrived at non-free entry in the non-full queue %d.\n"
"Please file bug report to %s.\n",
/*
* Add the descriptor in front of the skb.
*/
- skb_push(skb, ring->desc_size);
- memset(skb->data, 0, ring->desc_size);
+ skb_push(skb, queue->desc_size);
+ memset(skb->data, 0, queue->desc_size);
/*
* Fill in skb descriptor
*/
- desc = get_skb_desc(skb);
- desc->desc_len = ring->desc_size;
- desc->data_len = skb->len - ring->desc_size;
- desc->desc = skb->data;
- desc->data = skb->data + ring->desc_size;
- desc->ring = ring;
- desc->entry = entry;
+ skbdesc = get_skb_frame_desc(skb);
+ skbdesc->data = skb->data + queue->desc_size;
+ skbdesc->data_len = skb->len - queue->desc_size;
+ skbdesc->desc = skb->data;
+ skbdesc->desc_len = queue->desc_size;
+ skbdesc->entry = entry;
+ memcpy(&priv_tx->control, control, sizeof(priv_tx->control));
rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
/*
/*
* Initialize URB and send the frame to the device.
*/
- __set_bit(ENTRY_OWNER_NIC, &entry->flags);
- usb_fill_bulk_urb(entry->priv, usb_dev, usb_sndbulkpipe(usb_dev, 1),
+ __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ usb_fill_bulk_urb(priv_tx->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1),
skb->data, length, rt2x00usb_interrupt_txdone, entry);
- usb_submit_urb(entry->priv, GFP_ATOMIC);
+ usb_submit_urb(priv_tx->urb, GFP_ATOMIC);
- rt2x00_ring_index_inc(ring);
+ rt2x00queue_index_inc(queue, Q_INDEX);
return 0;
}
/*
* RX data handlers.
*/
+static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue)
+{
+ struct sk_buff *skb;
+ unsigned int frame_size;
+
+ /*
+ * As alignment we use 2 and not NET_IP_ALIGN because we need
+ * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN
+ * can be 0 on some hardware). We use these 2 bytes for frame
+ * alignment later, we assume that the chance that
+ * header_size % 4 == 2 is bigger then header_size % 2 == 0
+ * and thus optimize alignment by reserving the 2 bytes in
+ * advance.
+ */
+ frame_size = queue->data_size + queue->desc_size;
+ skb = dev_alloc_skb(queue->desc_size + frame_size + 2);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, queue->desc_size + 2);
+ skb_put(skb, frame_size);
+
+ return skb;
+}
+
static void rt2x00usb_interrupt_rxdone(struct urb *urb)
{
- struct data_entry *entry = (struct data_entry *)urb->context;
- struct data_ring *ring = entry->ring;
- struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+ struct queue_entry *entry = (struct queue_entry *)urb->context;
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct sk_buff *skb;
- struct ieee80211_hdr *hdr;
- struct skb_desc *skbdesc;
- struct rxdata_entry_desc desc;
+ struct skb_frame_desc *skbdesc;
+ struct rxdone_entry_desc rxdesc;
int header_size;
- int frame_size;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
- !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+ !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
* to be actually valid, or if the urb is signaling
* a problem.
*/
- if (urb->actual_length < entry->ring->desc_size || urb->status)
+ if (urb->actual_length < entry->queue->desc_size || urb->status)
goto skip_entry;
/*
* Fill in skb descriptor
*/
- skbdesc = get_skb_desc(entry->skb);
- skbdesc->ring = ring;
+ skbdesc = get_skb_frame_desc(entry->skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
- memset(&desc, 0, sizeof(desc));
- rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
-
- /*
- * Allocate a new sk buffer to replace the current one.
- * If allocation fails, we should drop the current frame
- * so we can recycle the existing sk buffer for the new frame.
- * As alignment we use 2 and not NET_IP_ALIGN because we need
- * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN
- * can be 0 on some hardware). We use these 2 bytes for frame
- * alignment later, we assume that the chance that
- * header_size % 4 == 2 is bigger then header_size % 2 == 0
- * and thus optimize alignment by reserving the 2 bytes in
- * advance.
- */
- frame_size = entry->ring->data_size + entry->ring->desc_size;
- skb = dev_alloc_skb(frame_size + 2);
- if (!skb)
- goto skip_entry;
-
- skb_reserve(skb, 2);
- skb_put(skb, frame_size);
+ memset(&rxdesc, 0, sizeof(rxdesc));
+ rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
/*
* The data behind the ieee80211 header must be
* aligned on a 4 byte boundary.
*/
- hdr = (struct ieee80211_hdr *)entry->skb->data;
- header_size =
- ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
-
+ header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
if (header_size % 4 == 0) {
skb_push(entry->skb, 2);
- memmove(entry->skb->data, entry->skb->data + 2, skb->len - 2);
+ memmove(entry->skb->data, entry->skb->data + 2,
+ entry->skb->len - 2);
+ skbdesc->data = entry->skb->data;
+ skb_trim(entry->skb,entry->skb->len - 2);
}
/*
- * Trim the entire buffer down to only contain the valid frame data
- * excluding the device descriptor. The position of the descriptor
- * varies. This means that we should check where the descriptor is
- * and decide if we need to pull the data pointer to exclude the
- * device descriptor.
+ * Allocate a new sk buffer to replace the current one.
+ * If allocation fails, we should drop the current frame
+ * so we can recycle the existing sk buffer for the new frame.
*/
- if (skbdesc->data > skbdesc->desc)
- skb_pull(entry->skb, skbdesc->desc_len);
- skb_trim(entry->skb, desc.size);
+ skb = rt2x00usb_alloc_rxskb(entry->queue);
+ if (!skb)
+ goto skip_entry;
/*
* Send the frame to rt2x00lib for further processing.
*/
- rt2x00lib_rxdone(entry, entry->skb, &desc);
+ rt2x00lib_rxdone(entry, &rxdesc);
/*
* Replace current entry's skb with the newly allocated one,
urb->transfer_buffer_length = entry->skb->len;
skip_entry:
- if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
- __set_bit(ENTRY_OWNER_NIC, &entry->flags);
+ if (test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) {
+ __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(urb, GFP_ATOMIC);
}
- rt2x00_ring_index_inc(ring);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX);
}
/*
*/
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
- struct data_ring *ring;
+ struct queue_entry_priv_usb_rx *priv_rx;
+ struct queue_entry_priv_usb_tx *priv_tx;
+ struct queue_entry_priv_usb_bcn *priv_bcn;
+ struct data_queue *queue;
unsigned int i;
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000,
REGISTER_TIMEOUT);
/*
- * Cancel all rings.
+ * Cancel all queues.
*/
- ring_for_each(rt2x00dev, ring) {
- for (i = 0; i < ring->stats.limit; i++)
- usb_kill_urb(ring->entry[i].priv);
+ for (i = 0; i < rt2x00dev->rx->limit; i++) {
+ priv_rx = rt2x00dev->rx->entries[i].priv_data;
+ usb_kill_urb(priv_rx->urb);
+ }
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ for (i = 0; i < queue->limit; i++) {
+ priv_tx = queue->entries[i].priv_data;
+ usb_kill_urb(priv_tx->urb);
+ }
+ }
+
+ for (i = 0; i < rt2x00dev->bcn->limit; i++) {
+ priv_bcn = rt2x00dev->bcn->entries[i].priv_data;
+ usb_kill_urb(priv_bcn->urb);
+
+ if (priv_bcn->guardian_urb)
+ usb_kill_urb(priv_bcn->guardian_urb);
+ }
+
+ if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
+ return;
+
+ for (i = 0; i < rt2x00dev->bcn[1].limit; i++) {
+ priv_tx = rt2x00dev->bcn[1].entries[i].priv_data;
+ usb_kill_urb(priv_tx->urb);
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
* Device initialization handlers.
*/
void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry)
+ struct queue_entry *entry)
{
- struct usb_device *usb_dev =
- interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
+ struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data;
- usb_fill_bulk_urb(entry->priv, usb_dev,
+ usb_fill_bulk_urb(priv_rx->urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 1),
entry->skb->data, entry->skb->len,
rt2x00usb_interrupt_rxdone, entry);
- __set_bit(ENTRY_OWNER_NIC, &entry->flags);
- usb_submit_urb(entry->priv, GFP_ATOMIC);
+ __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ usb_submit_urb(priv_rx->urb, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry)
+ struct queue_entry *entry)
{
entry->flags = 0;
}
EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry);
static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring)
+ struct data_queue *queue)
{
+ struct queue_entry_priv_usb_rx *priv_rx;
+ struct queue_entry_priv_usb_tx *priv_tx;
+ struct queue_entry_priv_usb_bcn *priv_bcn;
+ struct urb *urb;
+ unsigned int guardian =
+ test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
unsigned int i;
/*
* Allocate the URB's
*/
- for (i = 0; i < ring->stats.limit; i++) {
- ring->entry[i].priv = usb_alloc_urb(0, GFP_KERNEL);
- if (!ring->entry[i].priv)
+ for (i = 0; i < queue->limit; i++) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
return -ENOMEM;
+
+ if (queue->qid == QID_RX) {
+ priv_rx = queue->entries[i].priv_data;
+ priv_rx->urb = urb;
+ } else if (queue->qid == QID_MGMT && guardian) {
+ priv_bcn = queue->entries[i].priv_data;
+ priv_bcn->urb = urb;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+
+ priv_bcn->guardian_urb = urb;
+ } else {
+ priv_tx = queue->entries[i].priv_data;
+ priv_tx->urb = urb;
+ }
}
return 0;
}
static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring)
+ struct data_queue *queue)
{
+ struct queue_entry_priv_usb_rx *priv_rx;
+ struct queue_entry_priv_usb_tx *priv_tx;
+ struct queue_entry_priv_usb_bcn *priv_bcn;
+ struct urb *urb;
+ unsigned int guardian =
+ test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
unsigned int i;
- if (!ring->entry)
+ if (!queue->entries)
return;
- for (i = 0; i < ring->stats.limit; i++) {
- usb_kill_urb(ring->entry[i].priv);
- usb_free_urb(ring->entry[i].priv);
- if (ring->entry[i].skb)
- kfree_skb(ring->entry[i].skb);
+ for (i = 0; i < queue->limit; i++) {
+ if (queue->qid == QID_RX) {
+ priv_rx = queue->entries[i].priv_data;
+ urb = priv_rx->urb;
+ } else if (queue->qid == QID_MGMT && guardian) {
+ priv_bcn = queue->entries[i].priv_data;
+
+ usb_kill_urb(priv_bcn->guardian_urb);
+ usb_free_urb(priv_bcn->guardian_urb);
+
+ urb = priv_bcn->urb;
+ } else {
+ priv_tx = queue->entries[i].priv_data;
+ urb = priv_tx->urb;
+ }
+
+ usb_kill_urb(urb);
+ usb_free_urb(urb);
+ if (queue->entries[i].skb)
+ kfree_skb(queue->entries[i].skb);
}
}
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
{
- struct data_ring *ring;
+ struct data_queue *queue;
struct sk_buff *skb;
unsigned int entry_size;
unsigned int i;
/*
* Allocate DMA
*/
- ring_for_each(rt2x00dev, ring) {
- status = rt2x00usb_alloc_urb(rt2x00dev, ring);
+ queue_for_each(rt2x00dev, queue) {
+ status = rt2x00usb_alloc_urb(rt2x00dev, queue);
if (status)
goto exit;
}
/*
- * For the RX ring, skb's should be allocated.
+ * For the RX queue, skb's should be allocated.
*/
entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size;
- for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
- skb = dev_alloc_skb(NET_IP_ALIGN + entry_size);
+ for (i = 0; i < rt2x00dev->rx->limit; i++) {
+ skb = rt2x00usb_alloc_rxskb(rt2x00dev->rx);
if (!skb)
goto exit;
- skb_reserve(skb, NET_IP_ALIGN);
- skb_put(skb, entry_size);
-
- rt2x00dev->rx->entry[i].skb = skb;
+ rt2x00dev->rx->entries[i].skb = skb;
}
return 0;
void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
{
- struct data_ring *ring;
+ struct data_queue *queue;
- ring_for_each(rt2x00dev, ring)
- rt2x00usb_free_urb(rt2x00dev, ring);
+ queue_for_each(rt2x00dev, queue)
+ rt2x00usb_free_urb(rt2x00dev, queue);
}
EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
kfree(rt2x00dev->eeprom);
rt2x00dev->eeprom = NULL;
- kfree(rt2x00dev->csr_cache);
- rt2x00dev->csr_cache = NULL;
+ kfree(rt2x00dev->csr.cache);
+ rt2x00dev->csr.cache = NULL;
}
static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
- rt2x00dev->csr_cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
- if (!rt2x00dev->csr_cache)
+ rt2x00dev->csr.cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
+ if (!rt2x00dev->csr.cache)
goto exit;
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
#endif /* CONFIG_PM */
/*
- * rt2x00pci module information.
+ * rt2x00usb module information.
*/
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
-MODULE_DESCRIPTION("rt2x00 library");
+MODULE_DESCRIPTION("rt2x00 usb library");
MODULE_LICENSE("GPL");
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST )
#define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST )
-/*
- * USB vendor commands.
- */
-#define USB_DEVICE_MODE 0x01
-#define USB_SINGLE_WRITE 0x02
-#define USB_SINGLE_READ 0x03
-#define USB_MULTI_WRITE 0x06
-#define USB_MULTI_READ 0x07
-#define USB_EEPROM_WRITE 0x08
-#define USB_EEPROM_READ 0x09
-#define USB_LED_CONTROL 0x0a /* RT73USB */
-#define USB_RX_CONTROL 0x0c
+/**
+ * enum rt2x00usb_vendor_request: USB vendor commands.
+ */
+enum rt2x00usb_vendor_request {
+ USB_DEVICE_MODE = 1,
+ USB_SINGLE_WRITE = 2,
+ USB_SINGLE_READ = 3,
+ USB_MULTI_WRITE = 6,
+ USB_MULTI_READ = 7,
+ USB_EEPROM_WRITE = 8,
+ USB_EEPROM_READ = 9,
+ USB_LED_CONTROL = 10, /* RT73USB */
+ USB_RX_CONTROL = 12,
+};
-/*
- * Device modes offset
+/**
+ * enum rt2x00usb_mode_offset: Device modes offset.
*/
-#define USB_MODE_RESET 0x01
-#define USB_MODE_UNPLUG 0x02
-#define USB_MODE_FUNCTION 0x03
-#define USB_MODE_TEST 0x04
-#define USB_MODE_SLEEP 0x07 /* RT73USB */
-#define USB_MODE_FIRMWARE 0x08 /* RT73USB */
-#define USB_MODE_WAKEUP 0x09 /* RT73USB */
+enum rt2x00usb_mode_offset {
+ USB_MODE_RESET = 1,
+ USB_MODE_UNPLUG = 2,
+ USB_MODE_FUNCTION = 3,
+ USB_MODE_TEST = 4,
+ USB_MODE_SLEEP = 7, /* RT73USB */
+ USB_MODE_FIRMWARE = 8, /* RT73USB */
+ USB_MODE_WAKEUP = 9, /* RT73USB */
+};
-/*
- * Used to read/write from/to the device.
+/**
+ * rt2x00usb_vendor_request - Send register command to device
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
+ * @requesttype: Request type &USB_VENDOR_REQUEST_*
+ * @offset: Register offset to perform action on
+ * @value: Value to write to device
+ * @buffer: Buffer where information will be read/written to by device
+ * @buffer_length: Size of &buffer
+ * @timeout: Operation timeout
+ *
* This is the main function to communicate with the device,
- * the buffer argument _must_ either be NULL or point to
+ * the &buffer argument _must_ either be NULL or point to
* a buffer allocated by kmalloc. Failure to do so can lead
* to unexpected behavior depending on the architecture.
*/
void *buffer, const u16 buffer_length,
const int timeout);
-/*
- * Used to read/write from/to the device.
+/**
+ * rt2x00usb_vendor_request_buff - Send register command to device (buffered)
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
+ * @requesttype: Request type &USB_VENDOR_REQUEST_*
+ * @offset: Register offset to perform action on
+ * @buffer: Buffer where information will be read/written to by device
+ * @buffer_length: Size of &buffer
+ * @timeout: Operation timeout
+ *
* This function will use a previously with kmalloc allocated cache
* to communicate with the device. The contents of the buffer pointer
* will be copied to this cache when writing, or read from the cache
* when reading.
- * Buffers send to rt2x00usb_vendor_request _must_ be allocated with
+ * Buffers send to &rt2x00usb_vendor_request _must_ be allocated with
* kmalloc. Hence the reason for using a previously allocated cache
* which has been allocated properly.
*/
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout);
-/*
- * A version of rt2x00usb_vendor_request_buff which must be called
- * if the usb_cache_mutex is already held. */
+/**
+ * rt2x00usb_vendor_request_buff - Send register command to device (buffered)
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
+ * @requesttype: Request type &USB_VENDOR_REQUEST_*
+ * @offset: Register offset to perform action on
+ * @buffer: Buffer where information will be read/written to by device
+ * @buffer_length: Size of &buffer
+ * @timeout: Operation timeout
+ *
+ * A version of &rt2x00usb_vendor_request_buff which must be called
+ * if the usb_cache_mutex is already held.
+ */
int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout);
-/*
+/**
+ * rt2x00usb_vendor_request_sw - Send single register command to device
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
+ * @offset: Register offset to perform action on
+ * @value: Value to write to device
+ * @timeout: Operation timeout
+ *
* Simple wrapper around rt2x00usb_vendor_request to write a single
* command to the device. Since we don't use the buffer argument we
* don't have to worry about kmalloc here.
value, NULL, 0, timeout);
}
-/*
+/**
+ * rt2x00usb_eeprom_read - Read eeprom from device
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @eeprom: Pointer to eeprom array to store the information in
+ * @length: Number of bytes to read from the eeprom
+ *
* Simple wrapper around rt2x00usb_vendor_request to read the eeprom
* from the device. Note that the eeprom argument _must_ be allocated using
* kmalloc for correct handling inside the kernel USB layer.
int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16));
return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
- USB_VENDOR_REQUEST_IN, 0x0000,
- 0x0000, eeprom, lenght, timeout);
+ USB_VENDOR_REQUEST_IN, 0, 0,
+ eeprom, lenght, timeout);
}
/*
* TX data handlers.
*/
int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring, struct sk_buff *skb,
+ struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_tx_control *control);
+/**
+ * struct queue_entry_priv_usb_rx: Per RX entry USB specific information
+ *
+ * @urb: Urb structure used for device communication.
+ */
+struct queue_entry_priv_usb_rx {
+ struct urb *urb;
+};
+
+/**
+ * struct queue_entry_priv_usb_tx: Per TX entry USB specific information
+ *
+ * @urb: Urb structure used for device communication.
+ * @control: mac80211 control structure used to transmit data.
+ */
+struct queue_entry_priv_usb_tx {
+ struct urb *urb;
+
+ struct ieee80211_tx_control control;
+};
+
+/**
+ * struct queue_entry_priv_usb_tx: Per TX entry USB specific information
+ *
+ * The first section should match &struct queue_entry_priv_usb_tx exactly.
+ * rt2500usb can use this structure to send a guardian byte when working
+ * with beacons.
+ *
+ * @urb: Urb structure used for device communication.
+ * @control: mac80211 control structure used to transmit data.
+ * @guardian_data: Set to 0, used for sending the guardian data.
+ * @guardian_urb: Urb structure used to send the guardian data.
+ */
+struct queue_entry_priv_usb_bcn {
+ struct urb *urb;
+
+ struct ieee80211_tx_control control;
+
+ unsigned int guardian_data;
+ struct urb *guardian_urb;
+};
+
/*
* Device initialization handlers.
*/
void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry);
+ struct queue_entry *entry);
void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry);
+ struct queue_entry *entry);
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
Supported chipsets: RT2561, RT2561s, RT2661.
*/
+#include <linux/crc-itu-t.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
rt2x00_rf_write(rt2x00dev, word, value);
}
+#ifdef CONFIG_RT61PCI_LEDS
+/*
+ * This function is only called from rt61pci_led_brightness()
+ * make gcc happy by placing this function inside the
+ * same ifdef statement as the caller.
+ */
static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1)
rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1);
rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
}
+#endif /* CONFIG_RT61PCI_LEDS */
static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
{
u32 reg;
rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®);
- return rt2x00_get_field32(reg, MAC_CSR13_BIT5);;
+ return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
}
#else
#define rt61pci_rfkill_poll NULL
#endif /* CONFIG_RT61PCI_RFKILL */
+#ifdef CONFIG_RT61PCI_LEDS
+static void rt61pci_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ unsigned int enabled = brightness != LED_OFF;
+ unsigned int a_mode =
+ (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_5GHZ);
+ unsigned int bg_mode =
+ (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ);
+
+ if (led->type == LED_TYPE_RADIO) {
+ rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
+ MCU_LEDCS_RADIO_STATUS, enabled);
+
+ rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff,
+ (led->rt2x00dev->led_mcu_reg & 0xff),
+ ((led->rt2x00dev->led_mcu_reg >> 8)));
+ } else if (led->type == LED_TYPE_ASSOC) {
+ rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
+ MCU_LEDCS_LINK_BG_STATUS, bg_mode);
+ rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
+ MCU_LEDCS_LINK_A_STATUS, a_mode);
+
+ rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff,
+ (led->rt2x00dev->led_mcu_reg & 0xff),
+ ((led->rt2x00dev->led_mcu_reg >> 8)));
+ } else if (led->type == LED_TYPE_QUALITY) {
+ /*
+ * The brightness is divided into 6 levels (0 - 5),
+ * this means we need to convert the brightness
+ * argument into the matching level within that range.
+ */
+ rt61pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
+ brightness / (LED_FULL / 6), 0);
+ }
+}
+#else
+#define rt61pci_led_brightness NULL
+#endif /* CONFIG_RT61PCI_LEDS */
+
/*
* Configuration handlers.
*/
-static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac)
+static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct rt2x00intf_conf *conf,
+ const unsigned int flags)
{
- u32 tmp;
-
- tmp = le32_to_cpu(mac[1]);
- rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
- mac[1] = cpu_to_le32(tmp);
-
- rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
- (2 * sizeof(__le32)));
-}
+ unsigned int beacon_base;
+ u32 reg;
-static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
-{
- u32 tmp;
+ if (flags & CONFIG_UPDATE_TYPE) {
+ /*
+ * Clear current synchronisation setup.
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
+ rt2x00pci_register_write(rt2x00dev, beacon_base, 0);
- tmp = le32_to_cpu(bssid[1]);
- rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
- bssid[1] = cpu_to_le32(tmp);
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }
- rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
- (2 * sizeof(__le32)));
-}
+ if (flags & CONFIG_UPDATE_MAC) {
+ reg = le32_to_cpu(conf->mac[1]);
+ rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
+ conf->mac[1] = cpu_to_le32(reg);
-static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
- const int tsf_sync)
-{
- u32 reg;
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2,
+ conf->mac, sizeof(conf->mac));
+ }
- /*
- * Clear current synchronisation setup.
- * For the Beacon base registers we only need to clear
- * the first byte since that byte contains the VALID and OWNER
- * bits which (when set to 0) will invalidate the entire beacon.
- */
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
- rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
- rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
- rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
- rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+ if (flags & CONFIG_UPDATE_BSSID) {
+ reg = le32_to_cpu(conf->bssid[1]);
+ rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3);
+ conf->bssid[1] = cpu_to_le32(reg);
- /*
- * Enable synchronisation.
- */
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
- rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
- rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE,
- (tsf_sync == TSF_SYNC_BEACON));
- rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
- rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4,
+ conf->bssid, sizeof(conf->bssid));
+ }
}
-static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev,
- const int short_preamble,
- const int ack_timeout,
- const int ack_consume_time)
+static int rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp)
{
u32 reg;
rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®);
- rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
+ rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®);
rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE,
- !!short_preamble);
+ !!erp->short_preamble);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ return 0;
}
static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
case ANTENNA_HW_DIVERSITY:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
- (rt2x00dev->curr_hwmode != HWMODE_A));
+ (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ));
break;
case ANTENNA_A:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
- if (rt2x00dev->curr_hwmode == HWMODE_A)
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
else
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
break;
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
- if (rt2x00dev->curr_hwmode == HWMODE_A)
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
else
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
break;
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
break;
rt61pci_bbp_read(rt2x00dev, 4, &r4);
rt61pci_bbp_read(rt2x00dev, 77, &r77);
- /* FIXME: Antenna selection for the rf 2529 is very confusing in the
- * legacy driver. The code below should be ok for non-diversity setups.
- */
-
/*
* Configure the RX antenna.
*/
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
break;
- case ANTENNA_SW_DIVERSITY:
case ANTENNA_HW_DIVERSITY:
/*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
+ * FIXME: Antenna selection for the rf 2529 is very confusing
+ * in the legacy driver. Just default to antenna B until the
+ * legacy code can be properly translated into rt2x00 code.
*/
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
unsigned int i;
u32 reg;
- if (rt2x00dev->curr_hwmode == HWMODE_A) {
+ /*
+ * We should never come here because rt2x00lib is supposed
+ * to catch this and send us the correct antenna explicitely.
+ */
+ BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+ ant->tx == ANTENNA_SW_DIVERSITY);
+
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
sel = antenna_sel_a;
lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
} else {
rt2x00pci_register_read(rt2x00dev, PHY_CSR0, ®);
rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG,
- (rt2x00dev->curr_hwmode == HWMODE_B ||
- rt2x00dev->curr_hwmode == HWMODE_G));
+ rt2x00dev->curr_band == IEEE80211_BAND_2GHZ);
rt2x00_set_field32(®, PHY_CSR0_PA_PE_A,
- (rt2x00dev->curr_hwmode == HWMODE_A));
+ rt2x00dev->curr_band == IEEE80211_BAND_5GHZ);
rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
}
static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
- const unsigned int flags,
- struct rt2x00lib_conf *libconf)
+ struct rt2x00lib_conf *libconf,
+ const unsigned int flags)
{
if (flags & CONFIG_UPDATE_PHYMODE)
rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
}
/*
- * LED functions.
- */
-static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- u8 arg0;
- u8 arg1;
-
- rt2x00pci_register_read(rt2x00dev, MAC_CSR14, ®);
- rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70);
- rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg);
-
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1);
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS,
- (rt2x00dev->rx_status.phymode == MODE_IEEE80211A));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS,
- (rt2x00dev->rx_status.phymode != MODE_IEEE80211A));
-
- arg0 = rt2x00dev->led_reg & 0xff;
- arg1 = (rt2x00dev->led_reg >> 8) & 0xff;
-
- rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
-}
-
-static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev)
-{
- u16 led_reg;
- u8 arg0;
- u8 arg1;
-
- led_reg = rt2x00dev->led_reg;
- rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 0);
- rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 0);
- rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 0);
-
- arg0 = led_reg & 0xff;
- arg1 = (led_reg >> 8) & 0xff;
-
- rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
-}
-
-static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
-{
- u8 led;
-
- if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
- return;
-
- /*
- * Led handling requires a positive value for the rssi,
- * to do that correctly we need to add the correction.
- */
- rssi += rt2x00dev->rssi_offset;
-
- if (rssi <= 30)
- led = 0;
- else if (rssi <= 39)
- led = 1;
- else if (rssi <= 49)
- led = 2;
- else if (rssi <= 53)
- led = 3;
- else if (rssi <= 63)
- led = 4;
- else
- led = 5;
-
- rt61pci_mcu_request(rt2x00dev, MCU_LED_STRENGTH, 0xff, led, 0);
-}
-
-/*
* Link tuning
*/
static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev,
u8 up_bound;
u8 low_bound;
- /*
- * Update Led strength
- */
- rt61pci_activity_led(rt2x00dev, rssi);
-
rt61pci_bbp_read(rt2x00dev, 17, &r17);
/*
* Determine r17 bounds.
*/
- if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
low_bound = 0x28;
up_bound = 0x48;
if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
}
/*
+ * If we are not associated, we should go straight to the
+ * dynamic CCA tuning.
+ */
+ if (!rt2x00dev->intf_associated)
+ goto dynamic_cca_tune;
+
+ /*
* Special big-R17 for very short distance
*/
if (rssi >= -35) {
return;
}
+dynamic_cca_tune:
+
/*
* r17 does not yet exceed upper limit, continue and base
* the r17 tuning on the false CCA count.
}
/*
- * Firmware name function.
+ * Firmware functions
*/
static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
return fw_name;
}
-/*
- * Initialization functions.
- */
+static u16 rt61pci_get_firmware_crc(void *data, const size_t len)
+{
+ u16 crc;
+
+ /*
+ * Use the crc itu-t algorithm.
+ * The last 2 bytes in the firmware array are the crc checksum itself,
+ * this means that we should never pass those 2 bytes to the crc
+ * algorithm.
+ */
+ crc = crc_itu_t(0, data, len - 2);
+ crc = crc_itu_t_byte(crc, 0);
+ crc = crc_itu_t_byte(crc, 0);
+
+ return crc;
+}
+
static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
const size_t len)
{
return 0;
}
+/*
+ * Initialization functions.
+ */
static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry)
+ struct queue_entry *entry)
{
- __le32 *rxd = entry->priv;
+ struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
u32 word;
- rt2x00_desc_read(rxd, 5, &word);
+ rt2x00_desc_read(priv_rx->desc, 5, &word);
rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
- entry->data_dma);
- rt2x00_desc_write(rxd, 5, word);
+ priv_rx->data_dma);
+ rt2x00_desc_write(priv_rx->desc, 5, word);
- rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_desc_read(priv_rx->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(rxd, 0, word);
+ rt2x00_desc_write(priv_rx->desc, 0, word);
}
static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct data_entry *entry)
+ struct queue_entry *entry)
{
- __le32 *txd = entry->priv;
+ struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
u32 word;
- rt2x00_desc_read(txd, 1, &word);
+ rt2x00_desc_read(priv_tx->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
- rt2x00_desc_write(txd, 1, word);
+ rt2x00_desc_write(priv_tx->desc, 1, word);
- rt2x00_desc_read(txd, 5, &word);
- rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->ring->queue_idx);
+ rt2x00_desc_read(priv_tx->desc, 5, &word);
+ rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx);
- rt2x00_desc_write(txd, 5, word);
+ rt2x00_desc_write(priv_tx->desc, 5, word);
- rt2x00_desc_read(txd, 6, &word);
+ rt2x00_desc_read(priv_tx->desc, 6, &word);
rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
- entry->data_dma);
- rt2x00_desc_write(txd, 6, word);
+ priv_tx->data_dma);
+ rt2x00_desc_write(priv_tx->desc, 6, word);
- rt2x00_desc_read(txd, 0, &word);
+ rt2x00_desc_read(priv_tx->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(txd, 0, word);
+ rt2x00_desc_write(priv_tx->desc, 0, word);
}
-static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev)
+static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
+ struct queue_entry_priv_pci_rx *priv_rx;
+ struct queue_entry_priv_pci_tx *priv_tx;
u32 reg;
/*
*/
rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, ®);
rt2x00_set_field32(®, TX_RING_CSR0_AC0_RING_SIZE,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00dev->tx[0].limit);
rt2x00_set_field32(®, TX_RING_CSR0_AC1_RING_SIZE,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+ rt2x00dev->tx[1].limit);
rt2x00_set_field32(®, TX_RING_CSR0_AC2_RING_SIZE,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].stats.limit);
+ rt2x00dev->tx[2].limit);
rt2x00_set_field32(®, TX_RING_CSR0_AC3_RING_SIZE,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].stats.limit);
+ rt2x00dev->tx[3].limit);
rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg);
rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, ®);
- rt2x00_set_field32(®, TX_RING_CSR1_MGMT_RING_SIZE,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].stats.limit);
rt2x00_set_field32(®, TX_RING_CSR1_TXD_SIZE,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size /
- 4);
+ rt2x00dev->tx[0].desc_size / 4);
rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
+ priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, ®);
rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
+ priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, ®);
rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
+ priv_tx = rt2x00dev->tx[2].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, ®);
rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
+ priv_tx = rt2x00dev->tx[3].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, ®);
rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].data_dma);
+ priv_tx->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, MGMT_BASE_CSR, ®);
- rt2x00_set_field32(®, MGMT_BASE_CSR_RING_REGISTER,
- rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].data_dma);
- rt2x00pci_register_write(rt2x00dev, MGMT_BASE_CSR, reg);
-
rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, ®);
- rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE,
- rt2x00dev->rx->stats.limit);
+ rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit);
rt2x00_set_field32(®, RX_RING_CSR_RXD_SIZE,
rt2x00dev->rx->desc_size / 4);
rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
+ priv_rx = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, ®);
rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER,
- rt2x00dev->rx->data_dma);
+ priv_rx->desc_dma);
rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, ®);
rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC1, 2);
rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC2, 2);
rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC3, 2);
- rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_MGMT, 0);
rt2x00pci_register_write(rt2x00dev, TX_DMA_DST_CSR, reg);
rt2x00pci_register_read(rt2x00dev, LOAD_TX_RING_CSR, ®);
rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1);
rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1);
rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1);
- rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 1);
rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg);
rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, ®);
rt2x00pci_register_write(rt2x00dev, MAC_CSR13, 0x0000e000);
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR14, ®);
+ rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70);
+ rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg);
+
/*
* Invalidate all Shared Keys (SEC_CSR0),
* and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
/*
+ * Clear all beacons
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+
+ /*
* We must clear the error counters.
* These registers are cleared on read,
* so we may pass a useless variable to store the value.
rt61pci_bbp_write(rt2x00dev, 102, 0x16);
rt61pci_bbp_write(rt2x00dev, 107, 0x04);
- DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
for (i = 0; i < EEPROM_BBP_SIZE; i++) {
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
if (eeprom != 0xffff && eeprom != 0x0000) {
reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
- DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
- reg_id, value);
rt61pci_bbp_write(rt2x00dev, reg_id, value);
}
}
- DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
return 0;
}
/*
* Initialize all registers.
*/
- if (rt61pci_init_rings(rt2x00dev) ||
+ if (rt61pci_init_queues(rt2x00dev) ||
rt61pci_init_registers(rt2x00dev) ||
rt61pci_init_bbp(rt2x00dev)) {
ERROR(rt2x00dev, "Register initialization failed.\n");
rt2x00_set_field32(®, RX_CNTL_CSR_ENABLE_RX_DMA, 1);
rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
- /*
- * Enable LED
- */
- rt61pci_enable_led(rt2x00dev);
-
return 0;
}
{
u32 reg;
- /*
- * Disable LED
- */
- rt61pci_disable_led(rt2x00dev);
-
rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
/*
rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1);
rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1);
rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1);
- rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_MGMT, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
/*
*/
static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txdata_entry_desc *desc,
+ struct txentry_desc *txdesc,
struct ieee80211_tx_control *control)
{
- struct skb_desc *skbdesc = get_skb_desc(skb);
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
u32 word;
* Start writing the descriptor words.
*/
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
- rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
- rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
- rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
- rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
- rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
- rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
- rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 5, &word);
rt2x00_set_field32(&word, TXD_W5_TX_POWER,
- TXPOWER_TO_DEV(control->power_level));
+ TXPOWER_TO_DEV(rt2x00dev->tx_power));
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
- rt2x00_desc_read(txd, 11, &word);
- rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len);
- rt2x00_desc_write(txd, 11, word);
+ if (skbdesc->desc_len > TXINFO_SIZE) {
+ rt2x00_desc_read(txd, 11, &word);
+ rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len);
+ rt2x00_desc_write(txd, 11, word);
+ }
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
rt2x00_set_field32(&word, TXD_W0_VALID, 1);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
- test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK,
- test_bit(ENTRY_TXD_ACK, &desc->flags));
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
- test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_OFDM,
- test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
- rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags &
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_BURST,
- test_bit(ENTRY_TXD_BURST, &desc->flags));
+ test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word);
}
* TX data initialization
*/
static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- unsigned int queue)
+ const unsigned int queue)
{
u32 reg;
- if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ if (queue == RT2X00_BCN_QUEUE_BEACON) {
/*
* For Wi-Fi faily generated beacons between participating
* stations. Set TBTT phase adaptive adjustment step to 8us.
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
}
(queue == IEEE80211_TX_QUEUE_DATA2));
rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3,
(queue == IEEE80211_TX_QUEUE_DATA3));
- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_MGMT,
- (queue == IEEE80211_TX_QUEUE_DATA4));
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
}
return 0;
}
- if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
offset += 14;
return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
}
-static void rt61pci_fill_rxdone(struct data_entry *entry,
- struct rxdata_entry_desc *desc)
+static void rt61pci_fill_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
{
- __le32 *rxd = entry->priv;
+ struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
u32 word0;
u32 word1;
- rt2x00_desc_read(rxd, 0, &word0);
- rt2x00_desc_read(rxd, 1, &word1);
+ rt2x00_desc_read(priv_rx->desc, 0, &word0);
+ rt2x00_desc_read(priv_rx->desc, 1, &word1);
- desc->flags = 0;
+ rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
- desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
/*
* Obtain the status about this packet.
- */
- desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
- desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
- desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
+ * When frame was received with an OFDM bitrate,
+ * the signal is the PLCP value. If it was received with
+ * a CCK bitrate the signal is the rate in 100kbit/s.
+ */
+ rxdesc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ rxdesc->signal_plcp = rxdesc->ofdm;
+ rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1);
+ rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+ rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
}
/*
*/
static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
{
- struct data_ring *ring;
- struct data_entry *entry;
- struct data_entry *entry_done;
- __le32 *txd;
+ struct data_queue *queue;
+ struct queue_entry *entry;
+ struct queue_entry *entry_done;
+ struct queue_entry_priv_pci_tx *priv_tx;
+ struct txdone_entry_desc txdesc;
u32 word;
u32 reg;
u32 old_reg;
int type;
int index;
- int tx_status;
- int retry;
/*
* During each loop we will compare the freshly read
/*
* Skip this entry when it contains an invalid
- * ring identication number.
+ * queue identication number.
*/
type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE);
- ring = rt2x00lib_get_ring(rt2x00dev, type);
- if (unlikely(!ring))
+ queue = rt2x00queue_get_queue(rt2x00dev, type);
+ if (unlikely(!queue))
continue;
/*
* index number.
*/
index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE);
- if (unlikely(index >= ring->stats.limit))
+ if (unlikely(index >= queue->limit))
continue;
- entry = &ring->entry[index];
- txd = entry->priv;
- rt2x00_desc_read(txd, 0, &word);
+ entry = &queue->entries[index];
+ priv_tx = entry->priv_data;
+ rt2x00_desc_read(priv_tx->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID))
return;
- entry_done = rt2x00_get_data_entry_done(ring);
+ entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
while (entry != entry_done) {
- /* Catch up. Just report any entries we missed as
- * failed. */
+ /* Catch up.
+ * Just report any entries we missed as failed.
+ */
WARNING(rt2x00dev,
- "TX status report missed for entry %p\n",
- entry_done);
- rt2x00pci_txdone(rt2x00dev, entry_done, TX_FAIL_OTHER,
- 0);
- entry_done = rt2x00_get_data_entry_done(ring);
+ "TX status report missed for entry %d\n",
+ entry_done->entry_idx);
+
+ txdesc.status = TX_FAIL_OTHER;
+ txdesc.retry = 0;
+
+ rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
+ entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
}
/*
* Obtain the status about this packet.
*/
- tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
- retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
+ txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
+ txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
- rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
+ rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
}
}
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
- EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ EEPROM(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word);
} else {
value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
if (value < -10 || value > 10)
* If the eeprom value is invalid,
* switch to default led mode.
*/
+#ifdef CONFIG_RT61PCI_LEDS
rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
- rt2x00dev->led_mode = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE);
+ value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE);
+
+ switch (value) {
+ case LED_MODE_TXRX_ACTIVITY:
+ case LED_MODE_ASUS:
+ case LED_MODE_ALPHA:
+ case LED_MODE_DEFAULT:
+ rt2x00dev->led_flags =
+ LED_SUPPORT_RADIO | LED_SUPPORT_ASSOC;
+ break;
+ case LED_MODE_SIGNAL_STRENGTH:
+ rt2x00dev->led_flags =
+ LED_SUPPORT_RADIO | LED_SUPPORT_ASSOC |
+ LED_SUPPORT_QUALITY;
+ break;
+ }
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE,
- rt2x00dev->led_mode);
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value);
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_0));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_1,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_1));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_2,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_2));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_3,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_3));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_4,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_4));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_ACT,
rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_BG,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_RDY_G));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_RDY_A));
+#endif /* CONFIG_RT61PCI_LEDS */
return 0;
}
rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->max_signal = MAX_SIGNAL;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
- rt2x00dev->hw->queues = 5;
+ rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
/*
* Initialize hw_mode information.
*/
- spec->num_modes = 2;
- spec->num_rates = 12;
+ spec->supported_bands = SUPPORT_BAND_2GHZ;
+ spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
spec->tx_power_a = NULL;
spec->tx_power_bg = txpower;
spec->tx_power_default = DEFAULT_TXPOWER;
if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF5325)) {
- spec->num_modes = 3;
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_seq);
txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
rt61pci_probe_hw_mode(rt2x00dev);
/*
- * This device requires firmware
+ * This device requires firmware.
*/
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST,
!(*total_flags & FIF_ALLMULTI));
- rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, 0);
- rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1);
+ rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0);
+ rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS,
+ !(*total_flags & FIF_CONTROL));
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
}
return tsf;
}
-static void rt61pci_reset_tsf(struct ieee80211_hw *hw)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
-
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR12, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0);
-}
-
static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_control *control)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct skb_desc *desc;
- struct data_ring *ring;
- struct data_entry *entry;
+ struct rt2x00_intf *intf = vif_to_intf(control->vif);
+ struct skb_frame_desc *skbdesc;
+ unsigned int beacon_base;
+ u32 reg;
- /*
- * Just in case the ieee80211 doesn't set this,
- * but we need this queue set for the descriptor
- * initialization.
- */
- control->queue = IEEE80211_TX_QUEUE_BEACON;
- ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
- entry = rt2x00_get_data_entry(ring);
+ if (unlikely(!intf->beacon))
+ return -ENOBUFS;
/*
* We need to append the descriptor in front of the
* beacon frame.
*/
- if (skb_headroom(skb) < TXD_DESC_SIZE) {
- if (pskb_expand_head(skb, TXD_DESC_SIZE, 0, GFP_ATOMIC)) {
+ if (skb_headroom(skb) < intf->beacon->queue->desc_size) {
+ if (pskb_expand_head(skb, intf->beacon->queue->desc_size,
+ 0, GFP_ATOMIC)) {
dev_kfree_skb(skb);
return -ENOMEM;
}
/*
* Add the descriptor in front of the skb.
*/
- skb_push(skb, ring->desc_size);
- memset(skb->data, 0, ring->desc_size);
+ skb_push(skb, intf->beacon->queue->desc_size);
+ memset(skb->data, 0, intf->beacon->queue->desc_size);
/*
* Fill in skb descriptor
*/
- desc = get_skb_desc(skb);
- desc->desc_len = ring->desc_size;
- desc->data_len = skb->len - ring->desc_size;
- desc->desc = skb->data;
- desc->data = skb->data + ring->desc_size;
- desc->ring = ring;
- desc->entry = entry;
+ skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+ skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
+ skbdesc->data = skb->data + intf->beacon->queue->desc_size;
+ skbdesc->data_len = skb->len - intf->beacon->queue->desc_size;
+ skbdesc->desc = skb->data;
+ skbdesc->desc_len = intf->beacon->queue->desc_size;
+ skbdesc->entry = intf->beacon;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ /*
+ * mac80211 doesn't provide the control->queue variable
+ * for beacons. Set our own queue identification so
+ * it can be used during descriptor initialization.
+ */
+ control->queue = RT2X00_BCN_QUEUE_BEACON;
rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
/*
* Write entire beacon with descriptor to register,
* and kick the beacon generator.
*/
- rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0,
+ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
skb->data, skb->len);
- rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ rt61pci_kick_tx_queue(rt2x00dev, control->queue);
return 0;
}
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt61pci_get_tsf,
- .reset_tsf = rt61pci_reset_tsf,
.beacon_update = rt61pci_beacon_update,
};
.irq_handler = rt61pci_interrupt,
.probe_hw = rt61pci_probe_hw,
.get_firmware_name = rt61pci_get_firmware_name,
+ .get_firmware_crc = rt61pci_get_firmware_crc,
.load_firmware = rt61pci_load_firmware,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
.link_stats = rt61pci_link_stats,
.reset_tuner = rt61pci_reset_tuner,
.link_tuner = rt61pci_link_tuner,
+ .led_brightness = rt61pci_led_brightness,
.write_tx_desc = rt61pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt61pci_kick_tx_queue,
.fill_rxdone = rt61pci_fill_rxdone,
- .config_mac_addr = rt61pci_config_mac_addr,
- .config_bssid = rt61pci_config_bssid,
- .config_type = rt61pci_config_type,
- .config_preamble = rt61pci_config_preamble,
+ .config_intf = rt61pci_config_intf,
+ .config_erp = rt61pci_config_erp,
.config = rt61pci_config,
};
+static const struct data_queue_desc rt61pci_queue_rx = {
+ .entry_num = RX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = RXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_rx),
+};
+
+static const struct data_queue_desc rt61pci_queue_tx = {
+ .entry_num = TX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+};
+
+static const struct data_queue_desc rt61pci_queue_bcn = {
+ .entry_num = 4 * BEACON_ENTRIES,
+ .data_size = MGMT_FRAME_SIZE,
+ .desc_size = TXINFO_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+};
+
static const struct rt2x00_ops rt61pci_ops = {
.name = KBUILD_MODNAME,
- .rxd_size = RXD_DESC_SIZE,
- .txd_size = TXD_DESC_SIZE,
+ .max_sta_intf = 1,
+ .max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .rx = &rt61pci_queue_rx,
+ .tx = &rt61pci_queue_tx,
+ .bcn = &rt61pci_queue_bcn,
.lib = &rt61pci_rt2x00_ops,
.hw = &rt61pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#define HW_BEACON_BASE1 0x2d00
#define HW_BEACON_BASE2 0x2e00
#define HW_BEACON_BASE3 0x2f00
-#define HW_BEACON_OFFSET 0x0100
+
+#define HW_BEACON_OFFSET(__index) \
+ ( HW_BEACON_BASE0 + (__index * 0x0100) )
/*
* HOST-MCU shared memory.
/*
* MAC_CSR3: STA MAC register 1.
+ * UNICAST_TO_ME_MASK:
+ * Used to mask off bits from byte 5 of the MAC address
+ * to determine the UNICAST_TO_ME bit for RX frames.
+ * The full mask is complemented by BSS_ID_MASK:
+ * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK
*/
#define MAC_CSR3 0x300c
#define MAC_CSR3_BYTE4 FIELD32(0x000000ff)
/*
* MAC_CSR5: BSSID register 1.
- * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID.
+ * BSS_ID_MASK:
+ * This mask is used to mask off bits 0 and 1 of byte 5 of the
+ * BSSID. This will make sure that those bits will be ignored
+ * when determining the MY_BSS of RX frames.
+ * 0: 1-BSSID mode (BSS index = 0)
+ * 1: 2-BSSID mode (BSS index: Byte5, bit 0)
+ * 2: 2-BSSID mode (BSS index: byte5, bit 1)
+ * 3: 4-BSSID mode (BSS index: byte5, bit 0 - 1)
*/
#define MAC_CSR5 0x3014
#define MAC_CSR5_BYTE4 FIELD32(0x000000ff)
#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000)
#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000)
#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000)
-#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000)
+#define TXRX_CSR0_DROP_BROADCAST FIELD32(0x01000000)
#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000)
#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000)
#define TX_CNTL_CSR_ABORT_TX_MGMT FIELD32(0x00100000)
/*
- * LOAD_TX_RING_CSR: Load RX de
+ * LOAD_TX_RING_CSR: Load RX desriptor
*/
#define LOAD_TX_RING_CSR 0x3434
#define LOAD_TX_RING_CSR_LOAD_TXD_AC0 FIELD32(0x00000001)
#define EEPROM_MAC_ADDR_0 0x0002
#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
-#define EEPROM_MAC_ADDR1 0x0004
+#define EEPROM_MAC_ADDR1 0x0003
#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
-#define EEPROM_MAC_ADDR_2 0x0006
+#define EEPROM_MAC_ADDR_2 0x0004
#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE ( 16 * sizeof(__le32) )
+#define TXINFO_SIZE ( 6 * sizeof(__le32) )
#define RXD_DESC_SIZE ( 16 * sizeof(__le32) )
/*
#define RXD_W15_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to dscape value
- * and from dscape value to register value.
+ * Macro's for converting txpower from EEPROM to mac80211 value
+ * and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
#define MAX_TXPOWER 31
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
Supported chipsets: rt2571W & rt2671.
*/
+#include <linux/crc-itu-t.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-/*
- * Configuration handlers.
- */
-static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac)
+#ifdef CONFIG_RT73USB_LEDS
+static void rt73usb_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
{
- u32 tmp;
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ unsigned int enabled = brightness != LED_OFF;
+ unsigned int a_mode =
+ (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_5GHZ);
+ unsigned int bg_mode =
+ (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ);
- tmp = le32_to_cpu(mac[1]);
- rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
- mac[1] = cpu_to_le32(tmp);
+ if (in_atomic()) {
+ NOTICE(led->rt2x00dev,
+ "Ignoring LED brightness command for led %d\n",
+ led->type);
+ return;
+ }
- rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
- (2 * sizeof(__le32)));
+ if (led->type == LED_TYPE_RADIO) {
+ rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
+ MCU_LEDCS_RADIO_STATUS, enabled);
+
+ rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL,
+ 0, led->rt2x00dev->led_mcu_reg,
+ REGISTER_TIMEOUT);
+ } else if (led->type == LED_TYPE_ASSOC) {
+ rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
+ MCU_LEDCS_LINK_BG_STATUS, bg_mode);
+ rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
+ MCU_LEDCS_LINK_A_STATUS, a_mode);
+
+ rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL,
+ 0, led->rt2x00dev->led_mcu_reg,
+ REGISTER_TIMEOUT);
+ } else if (led->type == LED_TYPE_QUALITY) {
+ /*
+ * The brightness is divided into 6 levels (0 - 5),
+ * this means we need to convert the brightness
+ * argument into the matching level within that range.
+ */
+ rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL,
+ brightness / (LED_FULL / 6),
+ led->rt2x00dev->led_mcu_reg,
+ REGISTER_TIMEOUT);
+ }
}
+#else
+#define rt73usb_led_brightness NULL
+#endif /* CONFIG_RT73USB_LEDS */
-static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
+/*
+ * Configuration handlers.
+ */
+static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct rt2x00intf_conf *conf,
+ const unsigned int flags)
{
- u32 tmp;
+ unsigned int beacon_base;
+ u32 reg;
- tmp = le32_to_cpu(bssid[1]);
- rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
- bssid[1] = cpu_to_le32(tmp);
+ if (flags & CONFIG_UPDATE_TYPE) {
+ /*
+ * Clear current synchronisation setup.
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
+ rt73usb_register_write(rt2x00dev, beacon_base, 0);
- rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
- (2 * sizeof(__le32)));
-}
+ /*
+ * Enable synchronisation.
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }
-static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
- const int tsf_sync)
-{
- u32 reg;
+ if (flags & CONFIG_UPDATE_MAC) {
+ reg = le32_to_cpu(conf->mac[1]);
+ rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
+ conf->mac[1] = cpu_to_le32(reg);
- /*
- * Clear current synchronisation setup.
- * For the Beacon base registers we only need to clear
- * the first byte since that byte contains the VALID and OWNER
- * bits which (when set to 0) will invalidate the entire beacon.
- */
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+ rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2,
+ conf->mac, sizeof(conf->mac));
+ }
- /*
- * Enable synchronisation.
- */
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
- rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
- rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE,
- (tsf_sync == TSF_SYNC_BEACON));
- rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
- rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ if (flags & CONFIG_UPDATE_BSSID) {
+ reg = le32_to_cpu(conf->bssid[1]);
+ rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3);
+ conf->bssid[1] = cpu_to_le32(reg);
+
+ rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4,
+ conf->bssid, sizeof(conf->bssid));
+ }
}
-static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev,
- const int short_preamble,
- const int ack_timeout,
- const int ack_consume_time)
+static int rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp)
{
u32 reg;
/*
- * When in atomic context, reschedule and let rt2x00lib
- * call this function again.
+ * When in atomic context, we should let rt2x00lib
+ * try this configuration again later.
*/
- if (in_atomic()) {
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
- return;
- }
+ if (in_atomic())
+ return -EAGAIN;
rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®);
- rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
+ rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®);
rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE,
- !!short_preamble);
+ !!erp->short_preamble);
rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ return 0;
}
static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
case ANTENNA_HW_DIVERSITY:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)
- && (rt2x00dev->curr_hwmode != HWMODE_A);
+ && (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ);
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp);
break;
case ANTENNA_A:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
- if (rt2x00dev->curr_hwmode == HWMODE_A)
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
else
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
break;
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
- if (rt2x00dev->curr_hwmode == HWMODE_A)
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
else
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
break;
- case ANTENNA_SW_DIVERSITY:
- /*
- * NOTE: We should never come here because rt2x00lib is
- * supposed to catch this and send us the correct antenna
- * explicitely. However we are nog going to bug about this.
- * Instead, just default to antenna B.
- */
case ANTENNA_B:
+ default:
rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
break;
unsigned int i;
u32 reg;
- if (rt2x00dev->curr_hwmode == HWMODE_A) {
+ /*
+ * We should never come here because rt2x00lib is supposed
+ * to catch this and send us the correct antenna explicitely.
+ */
+ BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+ ant->tx == ANTENNA_SW_DIVERSITY);
+
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
sel = antenna_sel_a;
lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
} else {
rt73usb_register_read(rt2x00dev, PHY_CSR0, ®);
rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG,
- (rt2x00dev->curr_hwmode == HWMODE_B ||
- rt2x00dev->curr_hwmode == HWMODE_G));
+ (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ));
rt2x00_set_field32(®, PHY_CSR0_PA_PE_A,
- (rt2x00dev->curr_hwmode == HWMODE_A));
+ (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ));
rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
}
static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
- const unsigned int flags,
- struct rt2x00lib_conf *libconf)
+ struct rt2x00lib_conf *libconf,
+ const unsigned int flags)
{
if (flags & CONFIG_UPDATE_PHYMODE)
rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
}
/*
- * LED functions.
- */
-static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
-
- rt73usb_register_read(rt2x00dev, MAC_CSR14, ®);
- rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70);
- rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30);
- rt73usb_register_write(rt2x00dev, MAC_CSR14, reg);
-
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1);
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS,
- (rt2x00dev->rx_status.phymode == MODE_IEEE80211A));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS,
- (rt2x00dev->rx_status.phymode != MODE_IEEE80211A));
-
- rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
- rt2x00dev->led_reg, REGISTER_TIMEOUT);
-}
-
-static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev)
-{
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 0);
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, 0);
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, 0);
-
- rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
- rt2x00dev->led_reg, REGISTER_TIMEOUT);
-}
-
-static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
-{
- u32 led;
-
- if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
- return;
-
- /*
- * Led handling requires a positive value for the rssi,
- * to do that correctly we need to add the correction.
- */
- rssi += rt2x00dev->rssi_offset;
-
- if (rssi <= 30)
- led = 0;
- else if (rssi <= 39)
- led = 1;
- else if (rssi <= 49)
- led = 2;
- else if (rssi <= 53)
- led = 3;
- else if (rssi <= 63)
- led = 4;
- else
- led = 5;
-
- rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, led,
- rt2x00dev->led_reg, REGISTER_TIMEOUT);
-}
-
-/*
* Link tuning
*/
static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev,
u8 up_bound;
u8 low_bound;
- /*
- * Update Led strength
- */
- rt73usb_activity_led(rt2x00dev, rssi);
-
rt73usb_bbp_read(rt2x00dev, 17, &r17);
/*
* Determine r17 bounds.
*/
- if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
low_bound = 0x28;
up_bound = 0x48;
}
/*
+ * If we are not associated, we should go straight to the
+ * dynamic CCA tuning.
+ */
+ if (!rt2x00dev->intf_associated)
+ goto dynamic_cca_tune;
+
+ /*
* Special big-R17 for very short distance
*/
if (rssi > -35) {
return;
}
+dynamic_cca_tune:
+
/*
* r17 does not yet exceed upper limit, continue and base
* the r17 tuning on the false CCA count.
}
/*
- * Firmware name function.
+ * Firmware functions
*/
static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
return FIRMWARE_RT2571;
}
-/*
- * Initialization functions.
- */
+static u16 rt73usb_get_firmware_crc(void *data, const size_t len)
+{
+ u16 crc;
+
+ /*
+ * Use the crc itu-t algorithm.
+ * The last 2 bytes in the firmware array are the crc checksum itself,
+ * this means that we should never pass those 2 bytes to the crc
+ * algorithm.
+ */
+ crc = crc_itu_t(0, data, len - 2);
+ crc = crc_itu_t_byte(crc, 0);
+ crc = crc_itu_t_byte(crc, 0);
+
+ return crc;
+}
+
static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
const size_t len)
{
rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT,
- FIRMWARE_IMAGE_BASE + i, 0x0000,
+ FIRMWARE_IMAGE_BASE + i, 0,
cache, buflen, timeout);
ptr += buflen;
* we need to specify a long timeout time.
*/
status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE,
- 0x0000, USB_MODE_FIRMWARE,
+ 0, USB_MODE_FIRMWARE,
REGISTER_TIMEOUT_FIRMWARE);
if (status < 0) {
ERROR(rt2x00dev, "Failed to write Firmware to device.\n");
return status;
}
- rt73usb_disable_led(rt2x00dev);
-
return 0;
}
+/*
+ * Initialization functions.
+ */
static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
+ rt73usb_register_read(rt2x00dev, MAC_CSR14, ®);
+ rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70);
+ rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30);
+ rt73usb_register_write(rt2x00dev, MAC_CSR14, reg);
+
/*
* Invalidate all Shared Keys (SEC_CSR0),
* and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
/*
+ * Clear all beacons
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+
+ /*
* We must clear the error counters.
* These registers are cleared on read,
* so we may pass a useless variable to store the value.
rt73usb_bbp_write(rt2x00dev, 102, 0x16);
rt73usb_bbp_write(rt2x00dev, 107, 0x04);
- DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
for (i = 0; i < EEPROM_BBP_SIZE; i++) {
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
if (eeprom != 0xffff && eeprom != 0x0000) {
reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
- DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
- reg_id, value);
rt73usb_bbp_write(rt2x00dev, reg_id, value);
}
}
- DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
return 0;
}
return -EIO;
}
- /*
- * Enable LED
- */
- rt73usb_enable_led(rt2x00dev);
-
return 0;
}
static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
- /*
- * Disable LED
- */
- rt73usb_disable_led(rt2x00dev);
-
rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
/*
*/
static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txdata_entry_desc *desc,
+ struct txentry_desc *txdesc,
struct ieee80211_tx_control *control)
{
- struct skb_desc *skbdesc = get_skb_desc(skb);
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
u32 word;
* Start writing the descriptor words.
*/
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
- rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
- rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
- rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
- rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
- rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
- rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
- rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 5, &word);
rt2x00_set_field32(&word, TXD_W5_TX_POWER,
- TXPOWER_TO_DEV(control->power_level));
+ TXPOWER_TO_DEV(rt2x00dev->tx_power));
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_BURST,
- test_bit(ENTRY_TXD_BURST, &desc->flags));
+ test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_VALID, 1);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
- test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK,
- test_bit(ENTRY_TXD_ACK, &desc->flags));
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
- test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_OFDM,
- test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
- rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags &
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_BURST2,
- test_bit(ENTRY_TXD_BURST, &desc->flags));
+ test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word);
}
* TX data initialization
*/
static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- unsigned int queue)
+ const unsigned int queue)
{
u32 reg;
- if (queue != IEEE80211_TX_QUEUE_BEACON)
+ if (queue != RT2X00_BCN_QUEUE_BEACON)
return;
/*
rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1);
rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
return 0;
}
- if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
if (lna == 3 || lna == 2)
offset += 10;
return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
}
-static void rt73usb_fill_rxdone(struct data_entry *entry,
- struct rxdata_entry_desc *desc)
+static void rt73usb_fill_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
{
- struct skb_desc *skbdesc = get_skb_desc(entry->skb);
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxd = (__le32 *)entry->skb->data;
+ unsigned int offset = entry->queue->desc_size + 2;
u32 word0;
u32 word1;
+ /*
+ * Copy descriptor to the available headroom inside the skbuffer.
+ */
+ skb_push(entry->skb, offset);
+ memcpy(entry->skb->data, rxd, entry->queue->desc_size);
+ rxd = (__le32 *)entry->skb->data;
+
+ /*
+ * The descriptor is now aligned to 4 bytes and thus it is
+ * now safe to read it on all architectures.
+ */
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1);
- desc->flags = 0;
+ rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
- desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
/*
* Obtain the status about this packet.
+ * When frame was received with an OFDM bitrate,
+ * the signal is the PLCP value. If it was received with
+ * a CCK bitrate the signal is the rate in 100kbit/s.
+ */
+ rxdesc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ rxdesc->signal_plcp = rxdesc->ofdm;
+ rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1);
+ rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+ rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
+
+ /*
+ * Adjust the skb memory window to the frame boundaries.
*/
- desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
- desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
- desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
+ skb_pull(entry->skb, offset + entry->queue->desc_size);
+ skb_trim(entry->skb, rxdesc->size);
/*
* Set descriptor and data pointer.
*/
- skbdesc->desc = entry->skb->data;
- skbdesc->desc_len = entry->ring->desc_size;
- skbdesc->data = entry->skb->data + entry->ring->desc_size;
- skbdesc->data_len = desc->size;
+ skbdesc->data = entry->skb->data;
+ skbdesc->data_len = rxdesc->size;
+ skbdesc->desc = rxd;
+ skbdesc->desc_len = entry->queue->desc_size;
}
/*
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
- EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ EEPROM(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word);
} else {
value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
if (value < -10 || value > 10)
/*
* Store led settings, for correct led behaviour.
*/
+#ifdef CONFIG_RT73USB_LEDS
rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE,
- rt2x00dev->led_mode);
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0,
+ switch (value) {
+ case LED_MODE_TXRX_ACTIVITY:
+ case LED_MODE_ASUS:
+ case LED_MODE_ALPHA:
+ case LED_MODE_DEFAULT:
+ rt2x00dev->led_flags =
+ LED_SUPPORT_RADIO | LED_SUPPORT_ASSOC;
+ break;
+ case LED_MODE_SIGNAL_STRENGTH:
+ rt2x00dev->led_flags =
+ LED_SUPPORT_RADIO | LED_SUPPORT_ASSOC |
+ LED_SUPPORT_QUALITY;
+ break;
+ }
+
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value);
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_0));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_1,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_1));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_2,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_2));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_3,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_3));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_4,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_GPIO_4));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_ACT,
rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_BG,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_RDY_G));
- rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A,
+ rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A,
rt2x00_get_field16(eeprom,
EEPROM_LED_POLARITY_RDY_A));
+#endif /* CONFIG_RT73USB_LEDS */
return 0;
}
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->max_signal = MAX_SIGNAL;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
- rt2x00dev->hw->queues = 5;
+ rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
/*
* Initialize hw_mode information.
*/
- spec->num_modes = 2;
- spec->num_rates = 12;
+ spec->supported_bands = SUPPORT_BAND_2GHZ;
+ spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
spec->tx_power_a = NULL;
spec->tx_power_bg = txpower;
spec->tx_power_default = DEFAULT_TXPOWER;
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
spec->channels = rf_vals_bg_2528;
} else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5226);
spec->channels = rf_vals_5226;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) {
spec->num_channels = 14;
spec->channels = rf_vals_5225_2527;
} else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) {
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
spec->channels = rf_vals_5225_2527;
}
if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF5226)) {
- spec->num_modes = 3;
-
txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
for (i = 0; i < 14; i++)
txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
rt73usb_probe_hw_mode(rt2x00dev);
/*
- * This device requires firmware
+ * This device requires firmware.
*/
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST,
!(*total_flags & FIF_ALLMULTI));
rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0);
- rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1);
+ rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS,
+ !(*total_flags & FIF_CONTROL));
rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
}
#define rt73usb_get_tsf NULL
#endif
-static void rt73usb_reset_tsf(struct ieee80211_hw *hw)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
-
- rt73usb_register_write(rt2x00dev, TXRX_CSR12, 0);
- rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0);
-}
-
static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct ieee80211_tx_control *control)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct skb_desc *desc;
- struct data_ring *ring;
- struct data_entry *entry;
- int timeout;
+ struct rt2x00_intf *intf = vif_to_intf(control->vif);
+ struct skb_frame_desc *skbdesc;
+ unsigned int beacon_base;
+ unsigned int timeout;
+ u32 reg;
- /*
- * Just in case the ieee80211 doesn't set this,
- * but we need this queue set for the descriptor
- * initialization.
- */
- control->queue = IEEE80211_TX_QUEUE_BEACON;
- ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
- entry = rt2x00_get_data_entry(ring);
+ if (unlikely(!intf->beacon))
+ return -ENOBUFS;
/*
* Add the descriptor in front of the skb.
*/
- skb_push(skb, ring->desc_size);
- memset(skb->data, 0, ring->desc_size);
+ skb_push(skb, intf->beacon->queue->desc_size);
+ memset(skb->data, 0, intf->beacon->queue->desc_size);
/*
* Fill in skb descriptor
*/
- desc = get_skb_desc(skb);
- desc->desc_len = ring->desc_size;
- desc->data_len = skb->len - ring->desc_size;
- desc->desc = skb->data;
- desc->data = skb->data + ring->desc_size;
- desc->ring = ring;
- desc->entry = entry;
+ skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+ skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
+ skbdesc->data = skb->data + intf->beacon->queue->desc_size;
+ skbdesc->data_len = skb->len - intf->beacon->queue->desc_size;
+ skbdesc->desc = skb->data;
+ skbdesc->desc_len = intf->beacon->queue->desc_size;
+ skbdesc->entry = intf->beacon;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ /*
+ * mac80211 doesn't provide the control->queue variable
+ * for beacons. Set our own queue identification so
+ * it can be used during descriptor initialization.
+ */
+ control->queue = RT2X00_BCN_QUEUE_BEACON;
rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
/*
* Write entire beacon with descriptor to register,
* and kick the beacon generator.
*/
+ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32));
rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT,
- HW_BEACON_BASE0, 0x0000,
+ USB_VENDOR_REQUEST_OUT, beacon_base, 0,
skb->data, skb->len, timeout);
- rt73usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ rt73usb_kick_tx_queue(rt2x00dev, control->queue);
return 0;
}
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt73usb_get_tsf,
- .reset_tsf = rt73usb_reset_tsf,
.beacon_update = rt73usb_beacon_update,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.probe_hw = rt73usb_probe_hw,
.get_firmware_name = rt73usb_get_firmware_name,
+ .get_firmware_crc = rt73usb_get_firmware_crc,
.load_firmware = rt73usb_load_firmware,
.initialize = rt2x00usb_initialize,
.uninitialize = rt2x00usb_uninitialize,
.link_stats = rt73usb_link_stats,
.reset_tuner = rt73usb_reset_tuner,
.link_tuner = rt73usb_link_tuner,
+ .led_brightness = rt73usb_led_brightness,
.write_tx_desc = rt73usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
.get_tx_data_len = rt73usb_get_tx_data_len,
.kick_tx_queue = rt73usb_kick_tx_queue,
.fill_rxdone = rt73usb_fill_rxdone,
- .config_mac_addr = rt73usb_config_mac_addr,
- .config_bssid = rt73usb_config_bssid,
- .config_type = rt73usb_config_type,
- .config_preamble = rt73usb_config_preamble,
+ .config_intf = rt73usb_config_intf,
+ .config_erp = rt73usb_config_erp,
.config = rt73usb_config,
};
+static const struct data_queue_desc rt73usb_queue_rx = {
+ .entry_num = RX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = RXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_usb_rx),
+};
+
+static const struct data_queue_desc rt73usb_queue_tx = {
+ .entry_num = TX_ENTRIES,
+ .data_size = DATA_FRAME_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_usb_tx),
+};
+
+static const struct data_queue_desc rt73usb_queue_bcn = {
+ .entry_num = 4 * BEACON_ENTRIES,
+ .data_size = MGMT_FRAME_SIZE,
+ .desc_size = TXINFO_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_usb_tx),
+};
+
static const struct rt2x00_ops rt73usb_ops = {
.name = KBUILD_MODNAME,
- .rxd_size = RXD_DESC_SIZE,
- .txd_size = TXD_DESC_SIZE,
+ .max_sta_intf = 1,
+ .max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .rx = &rt73usb_queue_rx,
+ .tx = &rt73usb_queue_tx,
+ .bcn = &rt73usb_queue_bcn,
.lib = &rt73usb_rt2x00_ops,
.hw = &rt73usb_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
/*
- Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
#define HW_BEACON_BASE2 0x2600
#define HW_BEACON_BASE3 0x2700
+#define HW_BEACON_OFFSET(__index) \
+ ( HW_BEACON_BASE0 + (__index * 0x0100) )
+
/*
* MAC Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
/*
* MAC_CSR3: STA MAC register 1.
+ * UNICAST_TO_ME_MASK:
+ * Used to mask off bits from byte 5 of the MAC address
+ * to determine the UNICAST_TO_ME bit for RX frames.
+ * The full mask is complemented by BSS_ID_MASK:
+ * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK
*/
#define MAC_CSR3 0x300c
#define MAC_CSR3_BYTE4 FIELD32(0x000000ff)
/*
* MAC_CSR5: BSSID register 1.
- * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID.
+ * BSS_ID_MASK:
+ * This mask is used to mask off bits 0 and 1 of byte 5 of the
+ * BSSID. This will make sure that those bits will be ignored
+ * when determining the MY_BSS of RX frames.
+ * 0: 1-BSSID mode (BSS index = 0)
+ * 1: 2-BSSID mode (BSS index: Byte5, bit 0)
+ * 2: 2-BSSID mode (BSS index: byte5, bit 1)
+ * 3: 4-BSSID mode (BSS index: byte5, bit 0 - 1)
*/
#define MAC_CSR5 0x3014
#define MAC_CSR5_BYTE4 FIELD32(0x000000ff)
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE ( 6 * sizeof(__le32) )
+#define TXINFO_SIZE ( 6 * sizeof(__le32) )
#define RXD_DESC_SIZE ( 6 * sizeof(__le32) )
/*
#define RXD_W5_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to dscape value
- * and from dscape value to register value.
+ * Macro's for converting txpower from EEPROM to mac80211 value
+ * and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
#define MAX_TXPOWER 31
struct rtl8180_tx_ring tx_ring[4];
struct ieee80211_channel channels[14];
struct ieee80211_rate rates[12];
- struct ieee80211_hw_mode modes[2];
+ struct ieee80211_supported_band band;
struct pci_dev *pdev;
u32 rx_conf;
MODULE_DEVICE_TABLE(pci, rtl8180_table);
+static const struct ieee80211_rate rtl818x_rates[] = {
+ { .bitrate = 10, .hw_value = 0, },
+ { .bitrate = 20, .hw_value = 1, },
+ { .bitrate = 55, .hw_value = 2, },
+ { .bitrate = 110, .hw_value = 3, },
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+static const struct ieee80211_channel rtl818x_channels[] = {
+ { .center_freq = 2412 },
+ { .center_freq = 2417 },
+ { .center_freq = 2422 },
+ { .center_freq = 2427 },
+ { .center_freq = 2432 },
+ { .center_freq = 2437 },
+ { .center_freq = 2442 },
+ { .center_freq = 2447 },
+ { .center_freq = 2452 },
+ { .center_freq = 2457 },
+ { .center_freq = 2462 },
+ { .center_freq = 2467 },
+ { .center_freq = 2472 },
+ { .center_freq = 2484 },
+};
+
+
+
+
void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
{
struct rtl8180_priv *priv = dev->priv;
/* TODO: improve signal/rssi reporting */
rx_status.signal = flags2 & 0xFF;
rx_status.ssi = (flags2 >> 8) & 0x7F;
- rx_status.rate = (flags >> 20) & 0xF;
- rx_status.freq = dev->conf.freq;
- rx_status.channel = dev->conf.channel;
- rx_status.phymode = dev->conf.phymode;
+ /* XXX: is this correct? */
+ rx_status.rate_idx = (flags >> 20) & 0xF;
+ rx_status.freq = dev->conf.channel->center_freq;
+ rx_status.band = dev->conf.channel->band;
rx_status.mactime = le64_to_cpu(entry->tsft);
rx_status.flag |= RX_FLAG_TSFT;
if (flags & RTL8180_RX_DESC_FLAG_CRC32_ERR)
mapping = pci_map_single(priv->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE);
+ BUG_ON(!control->tx_rate);
+
tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS |
- RTL8180_TX_DESC_FLAG_LS | (control->tx_rate << 24) |
- (control->rts_cts_rate << 19) | skb->len;
+ RTL8180_TX_DESC_FLAG_LS |
+ (control->tx_rate->hw_value << 24) | skb->len;
if (priv->r8185)
tx_flags |= RTL8180_TX_DESC_FLAG_DMA |
RTL8180_TX_DESC_FLAG_NO_ENC;
- if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ BUG_ON(!control->rts_cts_rate);
tx_flags |= RTL8180_TX_DESC_FLAG_RTS;
- else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ tx_flags |= control->rts_cts_rate->hw_value << 19;
+ } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ BUG_ON(!control->rts_cts_rate);
tx_flags |= RTL8180_TX_DESC_FLAG_CTS;
+ tx_flags |= control->rts_cts_rate->hw_value << 19;
+ }
*((struct ieee80211_tx_control **) skb->cb) =
kmemdup(control, sizeof(*control), GFP_ATOMIC);
unsigned int remainder;
plcp_len = DIV_ROUND_UP(16 * (skb->len + 4),
- (control->rate->rate * 2) / 10);
+ (control->tx_rate->bitrate * 2) / 10);
remainder = (16 * (skb->len + 4)) %
- ((control->rate->rate * 2) / 10);
+ ((control->tx_rate->bitrate * 2) / 10);
if (remainder > 0 && remainder <= 6)
plcp_len |= 1 << 15;
}
entry->plcp_len = cpu_to_le16(plcp_len);
entry->tx_buf = cpu_to_le32(mapping);
entry->frame_len = cpu_to_le32(skb->len);
- entry->flags2 = control->alt_retry_rate != -1 ?
- control->alt_retry_rate << 4 : 0;
+ entry->flags2 = control->alt_retry_rate != NULL ?
+ control->alt_retry_rate->bitrate << 4 : 0;
entry->retry_limit = control->retry_limit;
entry->flags = cpu_to_le32(tx_flags);
__skb_queue_tail(&ring->queue, skb);
goto err_free_dev;
}
+ BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels));
+ BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates));
+
memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels));
memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates));
- priv->modes[0].mode = MODE_IEEE80211G;
- priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates);
- priv->modes[0].rates = priv->rates;
- priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels);
- priv->modes[0].channels = priv->channels;
- priv->modes[1].mode = MODE_IEEE80211B;
- priv->modes[1].num_rates = 4;
- priv->modes[1].rates = priv->rates;
- priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
- priv->modes[1].channels = priv->channels;
- priv->mode = IEEE80211_IF_TYPE_INVALID;
+
+ priv->band.band = IEEE80211_BAND_2GHZ;
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = ARRAY_SIZE(rtl818x_channels);
+ priv->band.bitrates = priv->rates;
+ priv->band.n_bitrates = 4;
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_RX_INCLUDES_FCS;
dev->queues = 1;
priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC;
if (priv->r8185) {
- if ((err = ieee80211_register_hwmode(dev, &priv->modes[0])))
- goto err_iounmap;
-
+ priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates);
pci_try_set_mwi(pdev);
}
- if ((err = ieee80211_register_hwmode(dev, &priv->modes[1])))
- goto err_iounmap;
-
eeprom.data = dev;
eeprom.register_read = rtl8180_eeprom_register_read;
eeprom.register_write = rtl8180_eeprom_register_write;
for (i = 0; i < 14; i += 2) {
u16 txpwr;
eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr);
- priv->channels[i].val = txpwr & 0xFF;
- priv->channels[i + 1].val = txpwr >> 8;
+ priv->channels[i].hw_value = txpwr & 0xFF;
+ priv->channels[i + 1].hw_value = txpwr >> 8;
}
/* OFDM TX power */
for (i = 0; i < 14; i += 2) {
u16 txpwr;
eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr);
- priv->channels[i].val |= (txpwr & 0xFF) << 8;
- priv->channels[i + 1].val |= txpwr & 0xFF00;
+ priv->channels[i].hw_value |= (txpwr & 0xFF) << 8;
+ priv->channels[i + 1].hw_value |= txpwr & 0xFF00;
}
}
struct ieee80211_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
- u32 txpw = priv->channels[conf->channel - 1].val & 0xFF;
- u32 chan = conf->channel - 1;
+ int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ u32 txpw = priv->channels[channel - 1].hw_value & 0xFF;
+ u32 chan = channel - 1;
/* set TX power */
write_grf5101(dev, 0x15, 0x0);
struct ieee80211_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
- unsigned int chan_idx = conf ? conf->channel - 1 : 0;
- u32 txpw = priv->channels[chan_idx].val & 0xFF;
+ int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ unsigned int chan_idx = channel - 1;
+ u32 txpw = priv->channels[chan_idx].hw_value & 0xFF;
u32 chan = max2820_chan[chan_idx];
/* While philips SA2400 drive the PA bias from
u32 reg;
int i;
- cck_power = priv->channels[channel - 1].val & 0xFF;
- ofdm_power = priv->channels[channel - 1].val >> 8;
+ cck_power = priv->channels[channel - 1].hw_value & 0xFF;
+ ofdm_power = priv->channels[channel - 1].hw_value >> 8;
cck_power = min(cck_power, (u8)35);
ofdm_power = min(ofdm_power, (u8)35);
const u8 *tmp;
int i;
- cck_power = priv->channels[channel - 1].val & 0xFF;
- ofdm_power = priv->channels[channel - 1].val >> 8;
+ cck_power = priv->channels[channel - 1].hw_value & 0xFF;
+ ofdm_power = priv->channels[channel - 1].hw_value >> 8;
if (channel == 14)
tmp = rtl8225z2_tx_power_cck_ch14;
struct ieee80211_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
+ int chan = ieee80211_frequency_to_channel(conf->channel->center_freq);
if (priv->rf->init == rtl8225_rf_init)
- rtl8225_rf_set_tx_power(dev, conf->channel);
+ rtl8225_rf_set_tx_power(dev, chan);
else
- rtl8225z2_rf_set_tx_power(dev, conf->channel);
+ rtl8225z2_rf_set_tx_power(dev, chan);
- rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]);
+ rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
msleep(10);
if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
struct ieee80211_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
- u32 txpw = priv->channels[conf->channel - 1].val & 0xFF;
- u32 chan = sa2400_chan[conf->channel - 1];
+ int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ u32 txpw = priv->channels[channel - 1].hw_value & 0xFF;
+ u32 chan = sa2400_chan[channel - 1];
write_sa2400(dev, 7, txpw);
/* rtl8187 specific */
struct ieee80211_channel channels[14];
struct ieee80211_rate rates[12];
- struct ieee80211_hw_mode modes[2];
+ struct ieee80211_supported_band band;
struct usb_device *udev;
u32 rx_conf;
u16 txpwr_base;
MODULE_DEVICE_TABLE(usb, rtl8187_table);
+static const struct ieee80211_rate rtl818x_rates[] = {
+ { .bitrate = 10, .hw_value = 0, },
+ { .bitrate = 20, .hw_value = 1, },
+ { .bitrate = 55, .hw_value = 2, },
+ { .bitrate = 110, .hw_value = 3, },
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+static const struct ieee80211_channel rtl818x_channels[] = {
+ { .center_freq = 2412 },
+ { .center_freq = 2417 },
+ { .center_freq = 2422 },
+ { .center_freq = 2427 },
+ { .center_freq = 2432 },
+ { .center_freq = 2437 },
+ { .center_freq = 2442 },
+ { .center_freq = 2447 },
+ { .center_freq = 2452 },
+ { .center_freq = 2457 },
+ { .center_freq = 2462 },
+ { .center_freq = 2467 },
+ { .center_freq = 2472 },
+ { .center_freq = 2484 },
+};
+
static void rtl8187_iowrite_async_cb(struct urb *urb)
{
kfree(urb->context);
flags = skb->len;
flags |= RTL8187_TX_FLAG_NO_ENCRYPT;
- flags |= control->rts_cts_rate << 19;
- flags |= control->tx_rate << 24;
+
+ BUG_ON(!control->tx_rate);
+
+ flags |= control->tx_rate->hw_value << 24;
if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data))
flags |= RTL8187_TX_FLAG_MORE_FRAG;
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ BUG_ON(!control->rts_cts_rate);
flags |= RTL8187_TX_FLAG_RTS;
+ flags |= control->rts_cts_rate->hw_value << 19;
rts_dur = ieee80211_rts_duration(dev, priv->vif,
skb->len, control);
- }
- if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ BUG_ON(!control->rts_cts_rate);
flags |= RTL8187_TX_FLAG_CTS;
+ flags |= control->rts_cts_rate->hw_value << 19;
+ }
hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
hdr->flags = cpu_to_le32(flags);
rx_status.antenna = (hdr->signal >> 7) & 1;
rx_status.signal = 64 - min(hdr->noise, (u8)64);
rx_status.ssi = signal;
- rx_status.rate = rate;
- rx_status.freq = dev->conf.freq;
- rx_status.channel = dev->conf.channel;
- rx_status.phymode = dev->conf.phymode;
+ rx_status.rate_idx = rate;
+ rx_status.freq = dev->conf.channel->center_freq;
+ rx_status.band = dev->conf.channel->band;
rx_status.mactime = le64_to_cpu(hdr->mac_time);
rx_status.flag |= RX_FLAG_TSFT;
if (flags & (1 << 13))
usb_get_dev(udev);
skb_queue_head_init(&priv->rx_queue);
+
+ BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels));
+ BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates));
+
memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels));
memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates));
priv->map = (struct rtl818x_csr *)0xFF00;
- priv->modes[0].mode = MODE_IEEE80211G;
- priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates);
- priv->modes[0].rates = priv->rates;
- priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels);
- priv->modes[0].channels = priv->channels;
- priv->modes[1].mode = MODE_IEEE80211B;
- priv->modes[1].num_rates = 4;
- priv->modes[1].rates = priv->rates;
- priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
- priv->modes[1].channels = priv->channels;
+
+ priv->band.band = IEEE80211_BAND_2GHZ;
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = ARRAY_SIZE(rtl818x_channels);
+ priv->band.bitrates = priv->rates;
+ priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates);
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+
+
priv->mode = IEEE80211_IF_TYPE_MNTR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_RX_INCLUDES_FCS;
dev->max_rssi = 65;
dev->max_signal = 64;
- for (i = 0; i < 2; i++)
- if ((err = ieee80211_register_hwmode(dev, &priv->modes[i])))
- goto err_free_dev;
-
eeprom.data = dev;
eeprom.register_read = rtl8187_eeprom_register_read;
eeprom.register_write = rtl8187_eeprom_register_write;
for (i = 0; i < 3; i++) {
eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i,
&txpwr);
- (*channel++).val = txpwr & 0xFF;
- (*channel++).val = txpwr >> 8;
+ (*channel++).hw_value = txpwr & 0xFF;
+ (*channel++).hw_value = txpwr >> 8;
}
for (i = 0; i < 2; i++) {
eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i,
&txpwr);
- (*channel++).val = txpwr & 0xFF;
- (*channel++).val = txpwr >> 8;
+ (*channel++).hw_value = txpwr & 0xFF;
+ (*channel++).hw_value = txpwr >> 8;
}
for (i = 0; i < 2; i++) {
eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6 + i,
&txpwr);
- (*channel++).val = txpwr & 0xFF;
- (*channel++).val = txpwr >> 8;
+ (*channel++).hw_value = txpwr & 0xFF;
+ (*channel++).hw_value = txpwr >> 8;
}
eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE,
u32 reg;
int i;
- cck_power = priv->channels[channel - 1].val & 0xF;
- ofdm_power = priv->channels[channel - 1].val >> 4;
+ cck_power = priv->channels[channel - 1].hw_value & 0xF;
+ ofdm_power = priv->channels[channel - 1].hw_value >> 4;
cck_power = min(cck_power, (u8)11);
ofdm_power = min(ofdm_power, (u8)35);
u32 reg;
int i;
- cck_power = priv->channels[channel - 1].val & 0xF;
- ofdm_power = priv->channels[channel - 1].val >> 4;
+ cck_power = priv->channels[channel - 1].hw_value & 0xF;
+ ofdm_power = priv->channels[channel - 1].hw_value >> 4;
cck_power = min(cck_power, (u8)15);
cck_power += priv->txpwr_base & 0xF;
struct ieee80211_conf *conf)
{
struct rtl8187_priv *priv = dev->priv;
+ int chan = ieee80211_frequency_to_channel(conf->channel->center_freq);
if (priv->rf->init == rtl8225_rf_init)
- rtl8225_rf_set_tx_power(dev, conf->channel);
+ rtl8225_rf_set_tx_power(dev, chan);
else
- rtl8225z2_rf_set_tx_power(dev, conf->channel);
+ rtl8225z2_rf_set_tx_power(dev, chan);
- rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]);
+ rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
msleep(10);
}
void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
};
-static const struct ieee80211_rate rtl818x_rates[] = {
- { .rate = 10,
- .val = 0,
- .flags = IEEE80211_RATE_CCK },
- { .rate = 20,
- .val = 1,
- .flags = IEEE80211_RATE_CCK },
- { .rate = 55,
- .val = 2,
- .flags = IEEE80211_RATE_CCK },
- { .rate = 110,
- .val = 3,
- .flags = IEEE80211_RATE_CCK },
- { .rate = 60,
- .val = 4,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 90,
- .val = 5,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 120,
- .val = 6,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 180,
- .val = 7,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 240,
- .val = 8,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 360,
- .val = 9,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 480,
- .val = 10,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 540,
- .val = 11,
- .flags = IEEE80211_RATE_OFDM },
-};
-
-static const struct ieee80211_channel rtl818x_channels[] = {
- { .chan = 1,
- .freq = 2412},
- { .chan = 2,
- .freq = 2417},
- { .chan = 3,
- .freq = 2422},
- { .chan = 4,
- .freq = 2427},
- { .chan = 5,
- .freq = 2432},
- { .chan = 6,
- .freq = 2437},
- { .chan = 7,
- .freq = 2442},
- { .chan = 8,
- .freq = 2447},
- { .chan = 9,
- .freq = 2452},
- { .chan = 10,
- .freq = 2457},
- { .chan = 11,
- .freq = 2462},
- { .chan = 12,
- .freq = 2467},
- { .chan = 13,
- .freq = 2472},
- { .chan = 14,
- .freq = 2484}
-};
-
#endif /* RTL818X_H */
/* get Nth element of the linked list */
static struct strip *strip_get_idx(loff_t pos)
{
- struct list_head *l;
+ struct strip *str;
int i = 0;
- list_for_each_rcu(l, &strip_list) {
+ list_for_each_entry_rcu(str, &strip_list, list) {
if (pos == i)
- return list_entry(l, struct strip, list);
+ return str;
++i;
}
return NULL;
{
static const struct zd_ioreq32 ioreqs[] = {
{ CR_ZD1211B_RETRY_MAX, 0x02020202 },
- { CR_ZD1211B_TX_PWR_CTL4, 0x007f003f },
- { CR_ZD1211B_TX_PWR_CTL3, 0x007f003f },
- { CR_ZD1211B_TX_PWR_CTL2, 0x003f001f },
- { CR_ZD1211B_TX_PWR_CTL1, 0x001f000f },
+ { CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f },
+ { CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f },
+ { CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f },
+ { CR_ZD1211B_CWIN_MAX_MIN_AC3, 0x001f000f },
{ CR_ZD1211B_AIFS_CTL1, 0x00280028 },
{ CR_ZD1211B_AIFS_CTL2, 0x008C003C },
{ CR_ZD1211B_TXOP, 0x01800824 },
{ CR_AFTER_PNP, 0x1 },
{ CR_WEP_PROTECT, 0x114 },
{ CR_IFS_VALUE, IFS_VALUE_DEFAULT },
+ { CR_CAM_MODE, MODE_AP_WDS},
};
ZD_ASSERT(mutex_is_locked(&chip->mutex));
return 0;
}
-static int set_mandatory_rates(struct zd_chip *chip, int mode)
+static int set_mandatory_rates(struct zd_chip *chip, int gmode)
{
u32 rates;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
* that the device is supporting. Until further notice we should try
* to support 802.11g also for full speed USB.
*/
- switch (mode) {
- case MODE_IEEE80211B:
+ if (!gmode)
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
- break;
- case MODE_IEEE80211G:
+ else
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
- break;
- default:
- return -EINVAL;
- }
+
return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL);
}
* It might be discussed, whether we should suppport pure b mode for
* full speed USB.
*/
- r = set_mandatory_rates(chip, MODE_IEEE80211G);
+ r = set_mandatory_rates(chip, 1);
if (r)
goto out;
/* Disabling interrupts is certainly a smart thing here.
#define CR_RX_OFFSET CTL_REG(0x065c)
+#define CR_BCN_LENGTH CTL_REG(0x0664)
#define CR_PHY_DELAY CTL_REG(0x066C)
#define CR_BCN_FIFO CTL_REG(0x0670)
#define CR_SNIFFER_ON CTL_REG(0x0674)
#define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \
RX_FILTER_CFEND | RX_FILTER_CFACK)
+#define BCN_MODE_IBSS 0x2000000
+
/* Monitor mode sets filter to 0xfffff */
#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
/* CAM: Continuous Access Mode (power management) */
#define CR_CAM_MODE CTL_REG(0x0700)
+#define MODE_IBSS 0x0
+#define MODE_AP 0x1
+#define MODE_STA 0x2
+#define MODE_AP_WDS 0x3
+
#define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704)
#define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708)
#define CR_CAM_ADDRESS CTL_REG(0x070C)
#define CR_S_MD CTL_REG(0x0830)
#define CR_USB_DEBUG_PORT CTL_REG(0x0888)
-
-#define CR_ZD1211B_TX_PWR_CTL1 CTL_REG(0x0b00)
-#define CR_ZD1211B_TX_PWR_CTL2 CTL_REG(0x0b04)
-#define CR_ZD1211B_TX_PWR_CTL3 CTL_REG(0x0b08)
-#define CR_ZD1211B_TX_PWR_CTL4 CTL_REG(0x0b0c)
+#define CR_ZD1211B_CWIN_MAX_MIN_AC0 CTL_REG(0x0b00)
+#define CR_ZD1211B_CWIN_MAX_MIN_AC1 CTL_REG(0x0b04)
+#define CR_ZD1211B_CWIN_MAX_MIN_AC2 CTL_REG(0x0b08)
+#define CR_ZD1211B_CWIN_MAX_MIN_AC3 CTL_REG(0x0b0c)
#define CR_ZD1211B_AIFS_CTL1 CTL_REG(0x0b10)
#define CR_ZD1211B_AIFS_CTL2 CTL_REG(0x0b14)
#define CR_ZD1211B_TXOP CTL_REG(0x0b20)
static void unmask_bg_channels(struct ieee80211_hw *hw,
const struct channel_range *range,
- struct ieee80211_hw_mode *mode)
+ struct ieee80211_supported_band *sband)
{
u8 channel;
for (channel = range->start; channel < range->end; channel++) {
struct ieee80211_channel *chan =
- &mode->channels[CHAN_TO_IDX(channel)];
- chan->flag |= IEEE80211_CHAN_W_SCAN |
- IEEE80211_CHAN_W_ACTIVE_SCAN |
- IEEE80211_CHAN_W_IBSS;
+ &sband->channels[CHAN_TO_IDX(channel)];
+ chan->flags = 0;
}
}
range = zd_channel_range(ZD_REGDOMAIN_FCC);
}
- unmask_bg_channels(hw, range, &mac->modes[0]);
- unmask_bg_channels(hw, range, &mac->modes[1]);
+ unmask_bg_channels(hw, range, &mac->band);
}
/* This table contains the hardware specific values for the modulation rates. */
static const struct ieee80211_rate zd_rates[] = {
- { .rate = 10,
- .val = ZD_CCK_RATE_1M,
- .flags = IEEE80211_RATE_CCK },
- { .rate = 20,
- .val = ZD_CCK_RATE_2M,
- .val2 = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 55,
- .val = ZD_CCK_RATE_5_5M,
- .val2 = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 110,
- .val = ZD_CCK_RATE_11M,
- .val2 = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT,
- .flags = IEEE80211_RATE_CCK_2 },
- { .rate = 60,
- .val = ZD_OFDM_RATE_6M,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 90,
- .val = ZD_OFDM_RATE_9M,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 120,
- .val = ZD_OFDM_RATE_12M,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 180,
- .val = ZD_OFDM_RATE_18M,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 240,
- .val = ZD_OFDM_RATE_24M,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 360,
- .val = ZD_OFDM_RATE_36M,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 480,
- .val = ZD_OFDM_RATE_48M,
- .flags = IEEE80211_RATE_OFDM },
- { .rate = 540,
- .val = ZD_OFDM_RATE_54M,
- .flags = IEEE80211_RATE_OFDM },
+ { .bitrate = 10,
+ .hw_value = ZD_CCK_RATE_1M, },
+ { .bitrate = 20,
+ .hw_value = ZD_CCK_RATE_2M,
+ .hw_value_short = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55,
+ .hw_value = ZD_CCK_RATE_5_5M,
+ .hw_value_short = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110,
+ .hw_value = ZD_CCK_RATE_11M,
+ .hw_value_short = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60,
+ .hw_value = ZD_OFDM_RATE_6M,
+ .flags = 0 },
+ { .bitrate = 90,
+ .hw_value = ZD_OFDM_RATE_9M,
+ .flags = 0 },
+ { .bitrate = 120,
+ .hw_value = ZD_OFDM_RATE_12M,
+ .flags = 0 },
+ { .bitrate = 180,
+ .hw_value = ZD_OFDM_RATE_18M,
+ .flags = 0 },
+ { .bitrate = 240,
+ .hw_value = ZD_OFDM_RATE_24M,
+ .flags = 0 },
+ { .bitrate = 360,
+ .hw_value = ZD_OFDM_RATE_36M,
+ .flags = 0 },
+ { .bitrate = 480,
+ .hw_value = ZD_OFDM_RATE_48M,
+ .flags = 0 },
+ { .bitrate = 540,
+ .hw_value = ZD_OFDM_RATE_54M,
+ .flags = 0 },
};
static const struct ieee80211_channel zd_channels[] = {
- { .chan = 1,
- .freq = 2412},
- { .chan = 2,
- .freq = 2417},
- { .chan = 3,
- .freq = 2422},
- { .chan = 4,
- .freq = 2427},
- { .chan = 5,
- .freq = 2432},
- { .chan = 6,
- .freq = 2437},
- { .chan = 7,
- .freq = 2442},
- { .chan = 8,
- .freq = 2447},
- { .chan = 9,
- .freq = 2452},
- { .chan = 10,
- .freq = 2457},
- { .chan = 11,
- .freq = 2462},
- { .chan = 12,
- .freq = 2467},
- { .chan = 13,
- .freq = 2472},
- { .chan = 14,
- .freq = 2484}
+ { .center_freq = 2412, .hw_value = 1 },
+ { .center_freq = 2417, .hw_value = 2 },
+ { .center_freq = 2422, .hw_value = 3 },
+ { .center_freq = 2427, .hw_value = 4 },
+ { .center_freq = 2432, .hw_value = 5 },
+ { .center_freq = 2437, .hw_value = 6 },
+ { .center_freq = 2442, .hw_value = 7 },
+ { .center_freq = 2447, .hw_value = 8 },
+ { .center_freq = 2452, .hw_value = 9 },
+ { .center_freq = 2457, .hw_value = 10 },
+ { .center_freq = 2462, .hw_value = 11 },
+ { .center_freq = 2467, .hw_value = 12 },
+ { .center_freq = 2472, .hw_value = 13 },
+ { .center_freq = 2484, .hw_value = 14 },
};
static void housekeeping_init(struct zd_mac *mac);
/* FIXME: Management frame? */
}
+void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
+{
+ struct zd_mac *mac = zd_hw_mac(hw);
+ u32 tmp, j = 0;
+ /* 4 more bytes for tail CRC */
+ u32 full_len = beacon->len + 4;
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0);
+ zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
+ while (tmp & 0x2) {
+ zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
+ if ((++j % 100) == 0) {
+ printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n");
+ if (j >= 500) {
+ printk(KERN_ERR "Giving up beacon config.\n");
+ return;
+ }
+ }
+ msleep(1);
+ }
+
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1);
+ if (zd_chip_is_zd1211b(&mac->chip))
+ zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1);
+
+ for (j = 0 ; j < beacon->len; j++)
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO,
+ *((u8 *)(beacon->data + j)));
+
+ for (j = 0; j < 4; j++)
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0);
+
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1);
+ /* 802.11b/g 2.4G CCK 1Mb
+ * 802.11a, not yet implemented, uses different values (see GPL vendor
+ * driver)
+ */
+ zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 |
+ (full_len << 19));
+}
+
static int fill_ctrlset(struct zd_mac *mac,
struct sk_buff *skb,
struct ieee80211_tx_control *control)
ZD_ASSERT(frag_len <= 0xffff);
- cs->modulation = control->tx_rate;
+ cs->modulation = control->tx_rate->hw_value;
+ if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+ cs->modulation = control->tx_rate->hw_value_short;
cs->tx_length = cpu_to_le16(frag_len);
int bad_frame = 0;
u16 fc;
bool is_qos, is_4addr, need_padding;
+ int i;
+ u8 rate;
if (length < ZD_PLCP_HEADER_SIZE + 10 /* IEEE80211_1ADDR_LEN */ +
FCS_LEN + sizeof(struct rx_status))
}
}
- stats.channel = _zd_chip_get_channel(&mac->chip);
- stats.freq = zd_channels[stats.channel - 1].freq;
- stats.phymode = MODE_IEEE80211G;
+ stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq;
+ stats.band = IEEE80211_BAND_2GHZ;
stats.ssi = status->signal_strength;
stats.signal = zd_rx_qual_percent(buffer,
length - sizeof(struct rx_status),
status);
- stats.rate = zd_rx_rate(buffer, status);
+
+ rate = zd_rx_rate(buffer, status);
+
+ /* todo: return index in the big switches in zd_rx_rate instead */
+ for (i = 0; i < mac->band.n_bitrates; i++)
+ if (rate == mac->band.bitrates[i].hw_value)
+ stats.rate_idx = i;
length -= ZD_PLCP_HEADER_SIZE + sizeof(struct rx_status);
buffer += ZD_PLCP_HEADER_SIZE;
switch (conf->type) {
case IEEE80211_IF_TYPE_MNTR:
+ case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
mac->type = conf->type;
break;
static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
{
struct zd_mac *mac = zd_hw_mac(hw);
- return zd_chip_set_channel(&mac->chip, conf->channel);
+ return zd_chip_set_channel(&mac->chip, conf->channel->hw_value);
}
static int zd_op_config_interface(struct ieee80211_hw *hw,
struct ieee80211_if_conf *conf)
{
struct zd_mac *mac = zd_hw_mac(hw);
+ int associated;
+
+ if (mac->type == IEEE80211_IF_TYPE_MESH_POINT) {
+ associated = true;
+ if (conf->beacon) {
+ zd_mac_config_beacon(hw, conf->beacon);
+ kfree_skb(conf->beacon);
+ zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
+ hw->conf.beacon_int);
+ }
+ } else
+ associated = is_valid_ether_addr(conf->bssid);
spin_lock_irq(&mac->lock);
- mac->associated = is_valid_ether_addr(conf->bssid);
+ mac->associated = associated;
spin_unlock_irq(&mac->lock);
/* TODO: do hardware bssid filtering */
return 0;
}
+void zd_process_intr(struct work_struct *work)
+{
+ u16 int_status;
+ struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
+
+ int_status = le16_to_cpu(*(u16 *)(mac->intr_buffer+4));
+ if (int_status & INT_CFG_NEXT_BCN) {
+ if (net_ratelimit())
+ dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
+ } else
+ dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n");
+
+ zd_chip_enable_hwint(&mac->chip);
+}
+
+
static void set_multicast_hash_handler(struct work_struct *work)
{
struct zd_mac *mac =
#define SUPPORTED_FIF_FLAGS \
(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
- FIF_OTHER_BSS)
+ FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
static void zd_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
{
struct zd_mac *mac;
struct ieee80211_hw *hw;
- int i;
hw = ieee80211_alloc_hw(sizeof(struct zd_mac), &zd_ops);
if (!hw) {
memcpy(mac->channels, zd_channels, sizeof(zd_channels));
memcpy(mac->rates, zd_rates, sizeof(zd_rates));
- mac->modes[0].mode = MODE_IEEE80211G;
- mac->modes[0].num_rates = ARRAY_SIZE(zd_rates);
- mac->modes[0].rates = mac->rates;
- mac->modes[0].num_channels = ARRAY_SIZE(zd_channels);
- mac->modes[0].channels = mac->channels;
- mac->modes[1].mode = MODE_IEEE80211B;
- mac->modes[1].num_rates = 4;
- mac->modes[1].rates = mac->rates;
- mac->modes[1].num_channels = ARRAY_SIZE(zd_channels);
- mac->modes[1].channels = mac->channels;
+ mac->band.n_bitrates = ARRAY_SIZE(zd_rates);
+ mac->band.bitrates = mac->rates;
+ mac->band.n_channels = ARRAY_SIZE(zd_channels);
+ mac->band.channels = mac->channels;
+
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
+ IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
hw->max_rssi = 100;
hw->max_signal = 100;
skb_queue_head_init(&mac->ack_wait_queue);
- for (i = 0; i < 2; i++) {
- if (ieee80211_register_hwmode(hw, &mac->modes[i])) {
- dev_dbg_f(&intf->dev, "cannot register hwmode\n");
- ieee80211_free_hw(hw);
- return NULL;
- }
- }
-
zd_chip_init(&mac->chip, hw, intf);
housekeeping_init(mac);
INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);
INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler);
+ INIT_WORK(&mac->process_intr, zd_process_intr);
SET_IEEE80211_DEV(hw, &intf->dev);
return hw;
struct zd_mac {
struct zd_chip chip;
spinlock_t lock;
+ spinlock_t intr_lock;
struct ieee80211_hw *hw;
struct housekeeping housekeeping;
struct work_struct set_multicast_hash_work;
struct work_struct set_rts_cts_work;
struct work_struct set_rx_filter_work;
+ struct work_struct process_intr;
struct zd_mc_hash multicast_hash;
+ u8 intr_buffer[USB_MAX_EP_INT_BUFFER];
u8 regdomain;
u8 default_regdomain;
int type;
struct sk_buff_head ack_wait_queue;
struct ieee80211_channel channels[14];
struct ieee80211_rate rates[12];
- struct ieee80211_hw_mode modes[2];
+ struct ieee80211_supported_band band;
/* Short preamble (used for RTS/CTS) */
unsigned int short_preamble:1;
#define FW_ZD1211B_PREFIX "zd1211/zd1211b_"
/* USB device initialization */
+static void int_urb_complete(struct urb *urb);
static int request_fw_file(
const struct firmware **fw, const char *name, struct device *device)
struct zd_usb *usb = urb->context;
struct zd_usb_interrupt *intr = &usb->intr;
int len;
+ u16 int_num;
ZD_ASSERT(in_interrupt());
spin_lock(&intr->lock);
- if (intr->read_regs_enabled) {
+ int_num = le16_to_cpu(*(u16 *)(urb->transfer_buffer+2));
+ if (int_num == CR_INTERRUPT) {
+ struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context));
+ memcpy(&mac->intr_buffer, urb->transfer_buffer,
+ USB_MAX_EP_INT_BUFFER);
+ schedule_work(&mac->process_intr);
+ } else if (intr->read_regs_enabled) {
intr->read_regs.length = len = urb->actual_length;
if (len > sizeof(intr->read_regs.buffer))
goto out;
}
- dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n");
out:
spin_unlock(&intr->lock);
}
struct qeth_ipaddr *addr;
struct qeth_card *card;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
QETH_DBF_TEXT(trace,3,"ipevent");
card = qeth_get_card_from_dev(dev);
if (!card)
If unsure, say N.
+# Common SPROM support routines
+config SSB_SPROM
+ bool
+
config SSB_PCIHOST_POSSIBLE
bool
depends on SSB && (PCI = y || PCI = SSB)
config SSB_PCIHOST
bool "Support for SSB on PCI-bus host"
depends on SSB_PCIHOST_POSSIBLE
+ select SSB_SPROM
default y
help
Support for a Sonics Silicon Backplane on top
config SSB_PCMCIAHOST
bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)"
depends on SSB_PCMCIAHOST_POSSIBLE
+ select SSB_SPROM
help
Support for a Sonics Silicon Backplane on top
of a PCMCIA device.
If unsure, say N
+config SSB_DRIVER_GIGE
+ bool "SSB Broadcom Gigabit Ethernet driver"
+ depends on SSB_PCIHOST_POSSIBLE && SSB_EMBEDDED && MIPS
+ help
+ Driver for the Sonics Silicon Backplane attached
+ Broadcom Gigabit Ethernet.
+
+ If unsure, say N
+
endmenu
# core
ssb-y += main.o scan.o
ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o
+ssb-$(CONFIG_SSB_SPROM) += sprom.o
# host support
ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
+ssb-$(CONFIG_SSB_DRIVER_GIGE) += driver_gige.o
# b43 pci-ssb-bridge driver
# Not strictly a part of SSB, but kept here for convenience
chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
}
+void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ chipco_write32_masked(cc, SSB_CHIPCO_IRQMASK, mask, value);
+}
+
+u32 ssb_chipco_irq_status(struct ssb_chipcommon *cc, u32 mask)
+{
+ return chipco_read32(cc, SSB_CHIPCO_IRQSTAT) & mask;
+}
+
u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
{
return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
--- /dev/null
+/*
+ * Sonics Silicon Backplane
+ * Broadcom Gigabit Ethernet core driver
+ *
+ * Copyright 2008, Broadcom Corporation
+ * Copyright 2008, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_driver_gige.h>
+#include <linux/pci.h>
+#include <linux/pci_regs.h>
+
+
+/*
+MODULE_DESCRIPTION("SSB Broadcom Gigabit Ethernet driver");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+*/
+
+static const struct ssb_device_id ssb_gige_tbl[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+};
+/* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */
+
+
+static inline u8 gige_read8(struct ssb_gige *dev, u16 offset)
+{
+ return ssb_read8(dev->dev, offset);
+}
+
+static inline u16 gige_read16(struct ssb_gige *dev, u16 offset)
+{
+ return ssb_read16(dev->dev, offset);
+}
+
+static inline u32 gige_read32(struct ssb_gige *dev, u16 offset)
+{
+ return ssb_read32(dev->dev, offset);
+}
+
+static inline void gige_write8(struct ssb_gige *dev,
+ u16 offset, u8 value)
+{
+ ssb_write8(dev->dev, offset, value);
+}
+
+static inline void gige_write16(struct ssb_gige *dev,
+ u16 offset, u16 value)
+{
+ ssb_write16(dev->dev, offset, value);
+}
+
+static inline void gige_write32(struct ssb_gige *dev,
+ u16 offset, u32 value)
+{
+ ssb_write32(dev->dev, offset, value);
+}
+
+static inline
+u8 gige_pcicfg_read8(struct ssb_gige *dev, unsigned int offset)
+{
+ BUG_ON(offset >= 256);
+ return gige_read8(dev, SSB_GIGE_PCICFG + offset);
+}
+
+static inline
+u16 gige_pcicfg_read16(struct ssb_gige *dev, unsigned int offset)
+{
+ BUG_ON(offset >= 256);
+ return gige_read16(dev, SSB_GIGE_PCICFG + offset);
+}
+
+static inline
+u32 gige_pcicfg_read32(struct ssb_gige *dev, unsigned int offset)
+{
+ BUG_ON(offset >= 256);
+ return gige_read32(dev, SSB_GIGE_PCICFG + offset);
+}
+
+static inline
+void gige_pcicfg_write8(struct ssb_gige *dev,
+ unsigned int offset, u8 value)
+{
+ BUG_ON(offset >= 256);
+ gige_write8(dev, SSB_GIGE_PCICFG + offset, value);
+}
+
+static inline
+void gige_pcicfg_write16(struct ssb_gige *dev,
+ unsigned int offset, u16 value)
+{
+ BUG_ON(offset >= 256);
+ gige_write16(dev, SSB_GIGE_PCICFG + offset, value);
+}
+
+static inline
+void gige_pcicfg_write32(struct ssb_gige *dev,
+ unsigned int offset, u32 value)
+{
+ BUG_ON(offset >= 256);
+ gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
+}
+
+static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 *val)
+{
+ struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
+ unsigned long flags;
+
+ if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (reg >= 256)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ switch (size) {
+ case 1:
+ *val = gige_pcicfg_read8(dev, reg);
+ break;
+ case 2:
+ *val = gige_pcicfg_read16(dev, reg);
+ break;
+ case 4:
+ *val = gige_pcicfg_read32(dev, reg);
+ break;
+ default:
+ WARN_ON(1);
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 val)
+{
+ struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
+ unsigned long flags;
+
+ if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (reg >= 256)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ switch (size) {
+ case 1:
+ gige_pcicfg_write8(dev, reg, val);
+ break;
+ case 2:
+ gige_pcicfg_write16(dev, reg, val);
+ break;
+ case 4:
+ gige_pcicfg_write32(dev, reg, val);
+ break;
+ default:
+ WARN_ON(1);
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int ssb_gige_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
+{
+ struct ssb_gige *dev;
+ u32 base, tmslow, tmshigh;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ dev->dev = sdev;
+
+ spin_lock_init(&dev->lock);
+ dev->pci_controller.pci_ops = &dev->pci_ops;
+ dev->pci_controller.io_resource = &dev->io_resource;
+ dev->pci_controller.mem_resource = &dev->mem_resource;
+ dev->pci_controller.io_map_base = 0x800;
+ dev->pci_ops.read = ssb_gige_pci_read_config;
+ dev->pci_ops.write = ssb_gige_pci_write_config;
+
+ dev->io_resource.name = SSB_GIGE_IO_RES_NAME;
+ dev->io_resource.start = 0x800;
+ dev->io_resource.end = 0x8FF;
+ dev->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
+
+ if (!ssb_device_is_enabled(sdev))
+ ssb_device_enable(sdev, 0);
+
+ /* Setup BAR0. This is a 64k MMIO region. */
+ base = ssb_admatch_base(ssb_read32(sdev, SSB_ADMATCH1));
+ gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_0, base);
+ gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_1, 0);
+
+ dev->mem_resource.name = SSB_GIGE_MEM_RES_NAME;
+ dev->mem_resource.start = base;
+ dev->mem_resource.end = base + 0x10000 - 1;
+ dev->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
+
+ /* Enable the memory region. */
+ gige_pcicfg_write16(dev, PCI_COMMAND,
+ gige_pcicfg_read16(dev, PCI_COMMAND)
+ | PCI_COMMAND_MEMORY);
+
+ /* Write flushing is controlled by the Flush Status Control register.
+ * We want to flush every register write with a timeout and we want
+ * to disable the IRQ mask while flushing to avoid concurrency.
+ * Note that automatic write flushing does _not_ work from
+ * an IRQ handler. The driver must flush manually by reading a register.
+ */
+ gige_write32(dev, SSB_GIGE_SHIM_FLUSHSTAT, 0x00000068);
+
+ /* Check if we have an RGMII or GMII PHY-bus.
+ * On RGMII do not bypass the DLLs */
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmshigh = ssb_read32(sdev, SSB_TMSHIGH);
+ if (tmshigh & SSB_GIGE_TMSHIGH_RGMII) {
+ tmslow &= ~SSB_GIGE_TMSLOW_TXBYPASS;
+ tmslow &= ~SSB_GIGE_TMSLOW_RXBYPASS;
+ dev->has_rgmii = 1;
+ } else {
+ tmslow |= SSB_GIGE_TMSLOW_TXBYPASS;
+ tmslow |= SSB_GIGE_TMSLOW_RXBYPASS;
+ dev->has_rgmii = 0;
+ }
+ tmslow |= SSB_GIGE_TMSLOW_DLLEN;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+
+ ssb_set_drvdata(sdev, dev);
+ register_pci_controller(&dev->pci_controller);
+
+ return 0;
+}
+
+bool pdev_is_ssb_gige_core(struct pci_dev *pdev)
+{
+ if (!pdev->resource[0].name)
+ return 0;
+ return (strcmp(pdev->resource[0].name, SSB_GIGE_MEM_RES_NAME) == 0);
+}
+EXPORT_SYMBOL(pdev_is_ssb_gige_core);
+
+int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
+ struct pci_dev *pdev)
+{
+ struct ssb_gige *dev = ssb_get_drvdata(sdev);
+ struct resource *res;
+
+ if (pdev->bus->ops != &dev->pci_ops) {
+ /* The PCI device is not on this SSB GigE bridge device. */
+ return -ENODEV;
+ }
+
+ /* Fixup the PCI resources. */
+ res = &(pdev->resource[0]);
+ res->flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
+ res->name = dev->mem_resource.name;
+ res->start = dev->mem_resource.start;
+ res->end = dev->mem_resource.end;
+
+ /* Fixup interrupt lines. */
+ pdev->irq = ssb_mips_irq(sdev) + 2;
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq);
+
+ return 0;
+}
+
+int ssb_gige_map_irq(struct ssb_device *sdev,
+ const struct pci_dev *pdev)
+{
+ struct ssb_gige *dev = ssb_get_drvdata(sdev);
+
+ if (pdev->bus->ops != &dev->pci_ops) {
+ /* The PCI device is not on this SSB GigE bridge device. */
+ return -ENODEV;
+ }
+
+ return ssb_mips_irq(sdev) + 2;
+}
+
+static struct ssb_driver ssb_gige_driver = {
+ .name = "BCM-GigE",
+ .id_table = ssb_gige_tbl,
+ .probe = ssb_gige_probe,
+};
+
+int ssb_gige_init(void)
+{
+ return ssb_driver_register(&ssb_gige_driver);
+}
/* fallthrough */
case SSB_DEV_PCI:
case SSB_DEV_ETHERNET:
+ case SSB_DEV_ETHERNET_GBIT:
case SSB_DEV_80211:
case SSB_DEV_USB20_HOST:
/* These devices get their own IRQ line if available, the rest goes on IRQ0 */
/* Core to access the external PCI config space. Can only have one. */
static struct ssb_pcicore *extpci_core;
-static u32 ssb_pcicore_pcibus_iobase = 0x100;
-static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
-
-int pcibios_plat_dev_init(struct pci_dev *d)
-{
- struct resource *res;
- int pos, size;
- u32 *base;
-
- ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
- pci_name(d));
-
- /* Fix up resource bases */
- for (pos = 0; pos < 6; pos++) {
- res = &d->resource[pos];
- if (res->flags & IORESOURCE_IO)
- base = &ssb_pcicore_pcibus_iobase;
- else
- base = &ssb_pcicore_pcibus_membase;
- res->flags |= IORESOURCE_PCI_FIXED;
- if (res->end) {
- size = res->end - res->start + 1;
- if (*base & (size - 1))
- *base = (*base + size) & ~(size - 1);
- res->start = *base;
- res->end = res->start + size - 1;
- *base += size;
- pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
- }
- /* Fix up PCI bridge BAR0 only */
- if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
- break;
- }
- /* Fix up interrupt lines */
- d->irq = ssb_mips_irq(extpci_core->dev) + 2;
- pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
-
- return 0;
-}
-
-static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
-{
- u8 lat;
-
- if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
- return;
-
- ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
-
- /* Enable PCI bridge bus mastering and memory space */
- pci_set_master(dev);
- if (pcibios_enable_device(dev, ~0) < 0) {
- ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
- return;
- }
-
- /* Enable PCI bridge BAR1 prefetch and burst */
- pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
-
- /* Make sure our latency is high enough to handle the devices behind us */
- lat = 168;
- ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
- pci_name(dev), lat);
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
-DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
-
-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
- return ssb_mips_irq(extpci_core->dev) + 2;
-}
static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
unsigned int bus, unsigned int dev,
.mem_offset = 0x24000000,
};
+static u32 ssb_pcicore_pcibus_iobase = 0x100;
+static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
+
+/* This function is called when doing a pci_enable_device().
+ * We must first check if the device is a device on the PCI-core bridge. */
+int ssb_pcicore_plat_dev_init(struct pci_dev *d)
+{
+ struct resource *res;
+ int pos, size;
+ u32 *base;
+
+ if (d->bus->ops != &ssb_pcicore_pciops) {
+ /* This is not a device on the PCI-core bridge. */
+ return -ENODEV;
+ }
+
+ ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
+ pci_name(d));
+
+ /* Fix up resource bases */
+ for (pos = 0; pos < 6; pos++) {
+ res = &d->resource[pos];
+ if (res->flags & IORESOURCE_IO)
+ base = &ssb_pcicore_pcibus_iobase;
+ else
+ base = &ssb_pcicore_pcibus_membase;
+ res->flags |= IORESOURCE_PCI_FIXED;
+ if (res->end) {
+ size = res->end - res->start + 1;
+ if (*base & (size - 1))
+ *base = (*base + size) & ~(size - 1);
+ res->start = *base;
+ res->end = res->start + size - 1;
+ *base += size;
+ pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
+ }
+ /* Fix up PCI bridge BAR0 only */
+ if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
+ break;
+ }
+ /* Fix up interrupt lines */
+ d->irq = ssb_mips_irq(extpci_core->dev) + 2;
+ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
+
+ return 0;
+}
+
+/* Early PCI fixup for a device on the PCI-core bridge. */
+static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev)
+{
+ u8 lat;
+
+ if (dev->bus->ops != &ssb_pcicore_pciops) {
+ /* This is not a device on the PCI-core bridge. */
+ return;
+ }
+ if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
+ return;
+
+ ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
+
+ /* Enable PCI bridge bus mastering and memory space */
+ pci_set_master(dev);
+ if (pcibios_enable_device(dev, ~0) < 0) {
+ ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
+ return;
+ }
+
+ /* Enable PCI bridge BAR1 prefetch and burst */
+ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
+
+ /* Make sure our latency is high enough to handle the devices behind us */
+ lat = 168;
+ ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
+ pci_name(dev), lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge);
+
+/* PCI device IRQ mapping. */
+int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (dev->bus->ops != &ssb_pcicore_pciops) {
+ /* This is not a device on the PCI-core bridge. */
+ return -ENODEV;
+ }
+ return ssb_mips_irq(extpci_core->dev) + 2;
+}
+
static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
{
u32 val;
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h>
+#include <linux/ssb/ssb_driver_pci.h>
+#include <linux/ssb/ssb_driver_gige.h>
+#include <linux/pci.h>
#include "ssb_private.h"
return res;
}
EXPORT_SYMBOL(ssb_gpio_polarity);
+
+#ifdef CONFIG_SSB_DRIVER_GIGE
+static int gige_pci_init_callback(struct ssb_bus *bus, unsigned long data)
+{
+ struct pci_dev *pdev = (struct pci_dev *)data;
+ struct ssb_device *dev;
+ unsigned int i;
+ int res;
+
+ for (i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT)
+ continue;
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ res = ssb_gige_pcibios_plat_dev_init(dev, pdev);
+ if (res >= 0)
+ return res;
+ }
+
+ return -ENODEV;
+}
+#endif /* CONFIG_SSB_DRIVER_GIGE */
+
+int ssb_pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ int err;
+
+ err = ssb_pcicore_plat_dev_init(dev);
+ if (!err)
+ return 0;
+#ifdef CONFIG_SSB_DRIVER_GIGE
+ err = ssb_for_each_bus_call((unsigned long)dev, gige_pci_init_callback);
+ if (err >= 0)
+ return err;
+#endif
+ /* This is not a PCI device on any SSB device. */
+
+ return -ENODEV;
+}
+
+#ifdef CONFIG_SSB_DRIVER_GIGE
+static int gige_map_irq_callback(struct ssb_bus *bus, unsigned long data)
+{
+ const struct pci_dev *pdev = (const struct pci_dev *)data;
+ struct ssb_device *dev;
+ unsigned int i;
+ int res;
+
+ for (i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT)
+ continue;
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ res = ssb_gige_map_irq(dev, pdev);
+ if (res >= 0)
+ return res;
+ }
+
+ return -ENODEV;
+}
+#endif /* CONFIG_SSB_DRIVER_GIGE */
+
+int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int res;
+
+ /* Check if this PCI device is a device on a SSB bus or device
+ * and return the IRQ number for it. */
+
+ res = ssb_pcicore_pcibios_map_irq(dev, slot, pin);
+ if (res >= 0)
+ return res;
+#ifdef CONFIG_SSB_DRIVER_GIGE
+ res = ssb_for_each_bus_call((unsigned long)dev, gige_map_irq_callback);
+ if (res >= 0)
+ return res;
+#endif
+ /* This is not a PCI device on any SSB device. */
+
+ return -ENODEV;
+}
#include <linux/io.h>
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_regs.h>
+#include <linux/ssb/ssb_driver_gige.h>
#include <linux/dma-mapping.h>
#include <linux/pci.h>
}
#endif /* CONFIG_SSB_PCIHOST */
+#ifdef CONFIG_SSB_PCMCIAHOST
+struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev)
+{
+ struct ssb_bus *bus;
+
+ ssb_buses_lock();
+ list_for_each_entry(bus, &buses, list) {
+ if (bus->bustype == SSB_BUSTYPE_PCMCIA &&
+ bus->host_pcmcia == pdev)
+ goto found;
+ }
+ bus = NULL;
+found:
+ ssb_buses_unlock();
+
+ return bus;
+}
+#endif /* CONFIG_SSB_PCMCIAHOST */
+
+int ssb_for_each_bus_call(unsigned long data,
+ int (*func)(struct ssb_bus *bus, unsigned long data))
+{
+ struct ssb_bus *bus;
+ int res;
+
+ ssb_buses_lock();
+ list_for_each_entry(bus, &buses, list) {
+ res = func(bus, data);
+ if (res >= 0) {
+ ssb_buses_unlock();
+ return res;
+ }
+ }
+ ssb_buses_unlock();
+
+ return -ENODEV;
+}
+
static struct ssb_device *ssb_device_get(struct ssb_device *dev)
{
if (dev)
list_del(&bus->list);
ssb_buses_unlock();
- /* ssb_pcmcia_exit(bus); */
+ ssb_pcmcia_exit(bus);
ssb_pci_exit(bus);
ssb_iounmap(bus);
}
return err;
}
+static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readb(bus->mmio + offset);
+}
+
static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
return readl(bus->mmio + offset);
}
+static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writeb(value, bus->mmio + offset);
+}
+
static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
{
struct ssb_bus *bus = dev->bus;
/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
static const struct ssb_bus_ops ssb_ssb_ops = {
+ .read8 = ssb_ssb_read8,
.read16 = ssb_ssb_read16,
.read32 = ssb_ssb_read32,
+ .write8 = ssb_ssb_write8,
.write16 = ssb_ssb_write16,
.write32 = ssb_ssb_write32,
};
err_dequeue:
list_del(&bus->list);
err_pcmcia_exit:
-/* ssb_pcmcia_exit(bus); */
+ ssb_pcmcia_exit(bus);
err_pci_exit:
ssb_pci_exit(bus);
err_unmap:
err = b43_pci_ssb_bridge_init();
if (err) {
ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
- "initialization failed");
+ "initialization failed\n");
+ /* don't fail SSB init because of this */
+ err = 0;
+ }
+ err = ssb_gige_init();
+ if (err) {
+ ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet "
+ "driver initialization failed\n");
/* don't fail SSB init because of this */
err = 0;
}
static void __exit ssb_modexit(void)
{
+ ssb_gige_exit();
b43_pci_ssb_bridge_exit();
bus_unregister(&ssb_bustype);
}
return crc;
}
-static int sprom_check_crc(const u16 *sprom, u16 size)
+static int sprom_check_crc(const u16 *sprom, size_t size)
{
u8 crc;
u8 expected_crc;
return 0;
}
-static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
+static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
{
int i;
for (i = 0; i < bus->sprom_size; i++)
sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
+
+ return 0;
}
static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
}
#endif /* DEBUG */
+static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return 0xFF;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return 0xFF;
+ }
+ return ioread8(bus->mmio + offset);
+}
+
static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
return ioread32(bus->mmio + offset);
}
+static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return;
+ }
+ iowrite8(value, bus->mmio + offset);
+}
+
static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
{
struct ssb_bus *bus = dev->bus;
/* Not "static", as it's used in main.c */
const struct ssb_bus_ops ssb_pci_ops = {
+ .read8 = ssb_pci_read8,
.read16 = ssb_pci_read16,
.read32 = ssb_pci_read32,
+ .write8 = ssb_pci_write8,
.write16 = ssb_pci_write16,
.write32 = ssb_pci_write32,
};
-static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size)
-{
- int i, pos = 0;
-
- for (i = 0; i < size; i++)
- pos += snprintf(buf + pos, buf_len - pos - 1,
- "%04X", swab16(sprom[i]) & 0xFFFF);
- pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
-
- return pos + 1;
-}
-
-static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size)
-{
- char tmp[5] = { 0 };
- int cnt = 0;
- unsigned long parsed;
-
- if (len < size * 2)
- return -EINVAL;
-
- while (cnt < size) {
- memcpy(tmp, dump, 4);
- dump += 4;
- parsed = simple_strtoul(tmp, NULL, 16);
- sprom[cnt++] = swab16((u16)parsed);
- }
-
- return 0;
-}
-
static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
struct ssb_bus *bus;
- u16 *sprom;
- int err = -ENODEV;
- ssize_t count = 0;
bus = ssb_pci_dev_to_bus(pdev);
if (!bus)
- goto out;
- err = -ENOMEM;
- sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
- if (!sprom)
- goto out;
-
- /* Use interruptible locking, as the SPROM write might
- * be holding the lock for several seconds. So allow userspace
- * to cancel operation. */
- err = -ERESTARTSYS;
- if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
- goto out_kfree;
- sprom_do_read(bus, sprom);
- mutex_unlock(&bus->pci_sprom_mutex);
-
- count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size);
- err = 0;
+ return -ENODEV;
-out_kfree:
- kfree(sprom);
-out:
- return err ? err : count;
+ return ssb_attr_sprom_show(bus, buf, sprom_do_read);
}
static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
{
struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
struct ssb_bus *bus;
- u16 *sprom;
- int res = 0, err = -ENODEV;
bus = ssb_pci_dev_to_bus(pdev);
if (!bus)
- goto out;
- err = -ENOMEM;
- sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
- if (!sprom)
- goto out;
- err = hex2sprom(sprom, buf, count, bus->sprom_size);
- if (err) {
- err = -EINVAL;
- goto out_kfree;
- }
- err = sprom_check_crc(sprom, bus->sprom_size);
- if (err) {
- err = -EINVAL;
- goto out_kfree;
- }
+ return -ENODEV;
- /* Use interruptible locking, as the SPROM write might
- * be holding the lock for several seconds. So allow userspace
- * to cancel operation. */
- err = -ERESTARTSYS;
- if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
- goto out_kfree;
- err = ssb_devices_freeze(bus);
- if (err == -EOPNOTSUPP) {
- ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
- "No suspend support. Is CONFIG_PM enabled?\n");
- goto out_unlock;
- }
- if (err) {
- ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
- goto out_unlock;
- }
- res = sprom_do_write(bus, sprom);
- err = ssb_devices_thaw(bus);
- if (err)
- ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
-out_unlock:
- mutex_unlock(&bus->pci_sprom_mutex);
-out_kfree:
- kfree(sprom);
-out:
- if (res)
- return res;
- return err ? err : count;
+ return ssb_attr_sprom_store(bus, buf, count,
+ sprom_check_crc, sprom_do_write);
}
static DEVICE_ATTR(ssb_sprom, 0600,
return 0;
pdev = bus->host_pci;
- mutex_init(&bus->pci_sprom_mutex);
+ mutex_init(&bus->sprom_mutex);
err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
if (err)
goto out;
* PCMCIA-Hostbus related functions
*
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/ssb/ssb.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/etherdevice.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0
+/* PCMCIA configuration registers */
+#define SSB_PCMCIA_CORECTL 0x00
+#define SSB_PCMCIA_CORECTL_RESET 0x80 /* Core reset */
+#define SSB_PCMCIA_CORECTL_IRQEN 0x04 /* IRQ enable */
+#define SSB_PCMCIA_CORECTL_FUNCEN 0x01 /* Function enable */
+#define SSB_PCMCIA_CORECTL2 0x80
+#define SSB_PCMCIA_ADDRESS0 0x2E
+#define SSB_PCMCIA_ADDRESS1 0x30
+#define SSB_PCMCIA_ADDRESS2 0x32
+#define SSB_PCMCIA_MEMSEG 0x34
+#define SSB_PCMCIA_SPROMCTL 0x36
+#define SSB_PCMCIA_SPROMCTL_IDLE 0
+#define SSB_PCMCIA_SPROMCTL_WRITE 1
+#define SSB_PCMCIA_SPROMCTL_READ 2
+#define SSB_PCMCIA_SPROMCTL_WRITEEN 4
+#define SSB_PCMCIA_SPROMCTL_WRITEDIS 7
+#define SSB_PCMCIA_SPROMCTL_DONE 8
+#define SSB_PCMCIA_SPROM_DATALO 0x38
+#define SSB_PCMCIA_SPROM_DATAHI 0x3A
+#define SSB_PCMCIA_SPROM_ADDRLO 0x3C
+#define SSB_PCMCIA_SPROM_ADDRHI 0x3E
+
+/* Hardware invariants CIS tuples */
+#define SSB_PCMCIA_CIS 0x80
+#define SSB_PCMCIA_CIS_ID 0x01
+#define SSB_PCMCIA_CIS_BOARDREV 0x02
+#define SSB_PCMCIA_CIS_PA 0x03
+#define SSB_PCMCIA_CIS_PA_PA0B0_LO 0
+#define SSB_PCMCIA_CIS_PA_PA0B0_HI 1
+#define SSB_PCMCIA_CIS_PA_PA0B1_LO 2
+#define SSB_PCMCIA_CIS_PA_PA0B1_HI 3
+#define SSB_PCMCIA_CIS_PA_PA0B2_LO 4
+#define SSB_PCMCIA_CIS_PA_PA0B2_HI 5
+#define SSB_PCMCIA_CIS_PA_ITSSI 6
+#define SSB_PCMCIA_CIS_PA_MAXPOW 7
+#define SSB_PCMCIA_CIS_OEMNAME 0x04
+#define SSB_PCMCIA_CIS_CCODE 0x05
+#define SSB_PCMCIA_CIS_ANTENNA 0x06
+#define SSB_PCMCIA_CIS_ANTGAIN 0x07
+#define SSB_PCMCIA_CIS_BFLAGS 0x08
+#define SSB_PCMCIA_CIS_LEDS 0x09
+
+/* PCMCIA SPROM size. */
+#define SSB_PCMCIA_SPROM_SIZE 256
+#define SSB_PCMCIA_SPROM_SIZE_BYTES (SSB_PCMCIA_SPROM_SIZE * sizeof(u16))
+
+
+/* Write to a PCMCIA configuration register. */
+static int ssb_pcmcia_cfg_write(struct ssb_bus *bus, u8 offset, u8 value)
+{
+ conf_reg_t reg;
+ int res;
+
+ memset(®, 0, sizeof(reg));
+ reg.Offset = offset;
+ reg.Action = CS_WRITE;
+ reg.Value = value;
+ res = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
+ if (unlikely(res != CS_SUCCESS))
+ return -EBUSY;
+
+ return 0;
+}
+
+/* Read from a PCMCIA configuration register. */
+static int ssb_pcmcia_cfg_read(struct ssb_bus *bus, u8 offset, u8 *value)
+{
+ conf_reg_t reg;
+ int res;
+
+ memset(®, 0, sizeof(reg));
+ reg.Offset = offset;
+ reg.Action = CS_READ;
+ res = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
+ if (unlikely(res != CS_SUCCESS))
+ return -EBUSY;
+ *value = reg.Value;
+
+ return 0;
+}
+
int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
u8 coreidx)
{
- struct pcmcia_device *pdev = bus->host_pcmcia;
int err;
int attempts = 0;
u32 cur_core;
- conf_reg_t reg;
u32 addr;
u32 read_addr;
+ u8 val;
addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
while (1) {
- reg.Action = CS_WRITE;
- reg.Offset = 0x2E;
- reg.Value = (addr & 0x0000F000) >> 12;
- err = pcmcia_access_configuration_register(pdev, ®);
- if (err != CS_SUCCESS)
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS0,
+ (addr & 0x0000F000) >> 12);
+ if (err)
goto error;
- reg.Offset = 0x30;
- reg.Value = (addr & 0x00FF0000) >> 16;
- err = pcmcia_access_configuration_register(pdev, ®);
- if (err != CS_SUCCESS)
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS1,
+ (addr & 0x00FF0000) >> 16);
+ if (err)
goto error;
- reg.Offset = 0x32;
- reg.Value = (addr & 0xFF000000) >> 24;
- err = pcmcia_access_configuration_register(pdev, ®);
- if (err != CS_SUCCESS)
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS2,
+ (addr & 0xFF000000) >> 24);
+ if (err)
goto error;
read_addr = 0;
- reg.Action = CS_READ;
- reg.Offset = 0x2E;
- err = pcmcia_access_configuration_register(pdev, ®);
- if (err != CS_SUCCESS)
+ err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS0, &val);
+ if (err)
goto error;
- read_addr |= ((u32)(reg.Value & 0x0F)) << 12;
- reg.Offset = 0x30;
- err = pcmcia_access_configuration_register(pdev, ®);
- if (err != CS_SUCCESS)
+ read_addr |= ((u32)(val & 0x0F)) << 12;
+ err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS1, &val);
+ if (err)
goto error;
- read_addr |= ((u32)reg.Value) << 16;
- reg.Offset = 0x32;
- err = pcmcia_access_configuration_register(pdev, ®);
- if (err != CS_SUCCESS)
+ read_addr |= ((u32)val) << 16;
+ err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS2, &val);
+ if (err)
goto error;
- read_addr |= ((u32)reg.Value) << 24;
+ read_addr |= ((u32)val) << 24;
cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
if (cur_core == coreidx)
break;
+ err = -ETIMEDOUT;
if (attempts++ > SSB_BAR0_MAX_RETRIES)
goto error;
udelay(10);
return 0;
error:
ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
- return -ENODEV;
+ return err;
}
int ssb_pcmcia_switch_core(struct ssb_bus *bus,
int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
{
int attempts = 0;
- conf_reg_t reg;
- int res;
+ int err;
+ u8 val;
SSB_WARN_ON((seg != 0) && (seg != 1));
- reg.Offset = 0x34;
- reg.Function = 0;
while (1) {
- reg.Action = CS_WRITE;
- reg.Value = seg;
- res = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
- if (unlikely(res != CS_SUCCESS))
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_MEMSEG, seg);
+ if (err)
goto error;
- reg.Value = 0xFF;
- reg.Action = CS_READ;
- res = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
- if (unlikely(res != CS_SUCCESS))
+ err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_MEMSEG, &val);
+ if (err)
goto error;
-
- if (reg.Value == seg)
+ if (val == seg)
break;
+ err = -ETIMEDOUT;
if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
goto error;
udelay(10);
return 0;
error:
ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
- return -ENODEV;
+ return err;
}
static int select_core_and_segment(struct ssb_device *dev,
return 0;
}
+static u8 ssb_pcmcia_read8(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+ unsigned long flags;
+ int err;
+ u8 value = 0xFF;
+
+ spin_lock_irqsave(&bus->bar_lock, flags);
+ err = select_core_and_segment(dev, &offset);
+ if (likely(!err))
+ value = readb(bus->mmio + offset);
+ spin_unlock_irqrestore(&bus->bar_lock, flags);
+
+ return value;
+}
+
static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
return (lo | (hi << 16));
}
+static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value)
+{
+ struct ssb_bus *bus = dev->bus;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&bus->bar_lock, flags);
+ err = select_core_and_segment(dev, &offset);
+ if (likely(!err))
+ writeb(value, bus->mmio + offset);
+ mmiowb();
+ spin_unlock_irqrestore(&bus->bar_lock, flags);
+}
+
static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
{
struct ssb_bus *bus = dev->bus;
/* Not "static", as it's used in main.c */
const struct ssb_bus_ops ssb_pcmcia_ops = {
+ .read8 = ssb_pcmcia_read8,
.read16 = ssb_pcmcia_read16,
.read32 = ssb_pcmcia_read32,
+ .write8 = ssb_pcmcia_write8,
.write16 = ssb_pcmcia_write16,
.write32 = ssb_pcmcia_write32,
};
-#include <linux/etherdevice.h>
+static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command)
+{
+ unsigned int i;
+ int err;
+ u8 value;
+
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROMCTL, command);
+ if (err)
+ return err;
+ for (i = 0; i < 1000; i++) {
+ err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROMCTL, &value);
+ if (err)
+ return err;
+ if (value & SSB_PCMCIA_SPROMCTL_DONE)
+ return 0;
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+/* offset is the 16bit word offset */
+static int ssb_pcmcia_sprom_read(struct ssb_bus *bus, u16 offset, u16 *value)
+{
+ int err;
+ u8 lo, hi;
+
+ offset *= 2; /* Make byte offset */
+
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO,
+ (offset & 0x00FF));
+ if (err)
+ return err;
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI,
+ (offset & 0xFF00) >> 8);
+ if (err)
+ return err;
+ err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_READ);
+ if (err)
+ return err;
+ err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATALO, &lo);
+ if (err)
+ return err;
+ err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATAHI, &hi);
+ if (err)
+ return err;
+ *value = (lo | (((u16)hi) << 8));
+
+ return 0;
+}
+
+/* offset is the 16bit word offset */
+static int ssb_pcmcia_sprom_write(struct ssb_bus *bus, u16 offset, u16 value)
+{
+ int err;
+
+ offset *= 2; /* Make byte offset */
+
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO,
+ (offset & 0x00FF));
+ if (err)
+ return err;
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI,
+ (offset & 0xFF00) >> 8);
+ if (err)
+ return err;
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATALO,
+ (value & 0x00FF));
+ if (err)
+ return err;
+ err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATAHI,
+ (value & 0xFF00) >> 8);
+ if (err)
+ return err;
+ err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITE);
+ if (err)
+ return err;
+ msleep(20);
+
+ return 0;
+}
+
+/* Read the SPROM image. bufsize is in 16bit words. */
+static int ssb_pcmcia_sprom_read_all(struct ssb_bus *bus, u16 *sprom)
+{
+ int err, i;
+
+ for (i = 0; i < SSB_PCMCIA_SPROM_SIZE; i++) {
+ err = ssb_pcmcia_sprom_read(bus, i, &sprom[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Write the SPROM image. size is in 16bit words. */
+static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)
+{
+ int i, err;
+ bool failed = 0;
+ size_t size = SSB_PCMCIA_SPROM_SIZE;
+
+ ssb_printk(KERN_NOTICE PFX
+ "Writing SPROM. Do NOT turn off the power! "
+ "Please stand by...\n");
+ err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN);
+ if (err) {
+ ssb_printk(KERN_NOTICE PFX
+ "Could not enable SPROM write access.\n");
+ return -EBUSY;
+ }
+ ssb_printk(KERN_NOTICE PFX "[ 0%%");
+ msleep(500);
+ for (i = 0; i < size; i++) {
+ if (i == size / 4)
+ ssb_printk("25%%");
+ else if (i == size / 2)
+ ssb_printk("50%%");
+ else if (i == (size * 3) / 4)
+ ssb_printk("75%%");
+ else if (i % 2)
+ ssb_printk(".");
+ err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);
+ if (err) {
+ ssb_printk("\n" KERN_NOTICE PFX
+ "Failed to write to SPROM.\n");
+ failed = 1;
+ break;
+ }
+ }
+ err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);
+ if (err) {
+ ssb_printk("\n" KERN_NOTICE PFX
+ "Could not disable SPROM write access.\n");
+ failed = 1;
+ }
+ msleep(500);
+ if (!failed) {
+ ssb_printk("100%% ]\n");
+ ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
+ }
+
+ return failed ? -EBUSY : 0;
+}
+
+static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size)
+{
+ //TODO
+ return 0;
+}
+
+#define GOTO_ERROR_ON(condition, description) do { \
+ if (unlikely(condition)) { \
+ error_description = description; \
+ goto error; \
+ } \
+ } while (0)
+
int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv)
{
- //TODO
- random_ether_addr(iv->sprom.il0mac);
+ tuple_t tuple;
+ int res;
+ unsigned char buf[32];
+ struct ssb_sprom *sprom = &iv->sprom;
+ struct ssb_boardinfo *bi = &iv->boardinfo;
+ const char *error_description;
+
+ memset(sprom, 0xFF, sizeof(*sprom));
+ sprom->revision = 1;
+ sprom->boardflags_lo = 0;
+ sprom->boardflags_hi = 0;
+
+ /* First fetch the MAC address. */
+ memset(&tuple, 0, sizeof(tuple));
+ tuple.DesiredTuple = CISTPL_FUNCE;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
+ GOTO_ERROR_ON(res != CS_SUCCESS, "MAC first tpl");
+ res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
+ GOTO_ERROR_ON(res != CS_SUCCESS, "MAC first tpl data");
+ while (1) {
+ GOTO_ERROR_ON(tuple.TupleDataLen < 1, "MAC tpl < 1");
+ if (tuple.TupleData[0] == CISTPL_FUNCE_LAN_NODE_ID)
+ break;
+ res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
+ GOTO_ERROR_ON(res != CS_SUCCESS, "MAC next tpl");
+ res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
+ GOTO_ERROR_ON(res != CS_SUCCESS, "MAC next tpl data");
+ }
+ GOTO_ERROR_ON(tuple.TupleDataLen != ETH_ALEN + 2, "MAC tpl size");
+ memcpy(sprom->il0mac, &tuple.TupleData[2], ETH_ALEN);
+
+ /* Fetch the vendor specific tuples. */
+ memset(&tuple, 0, sizeof(tuple));
+ tuple.DesiredTuple = SSB_PCMCIA_CIS;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
+ GOTO_ERROR_ON(res != CS_SUCCESS, "VEN first tpl");
+ res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
+ GOTO_ERROR_ON(res != CS_SUCCESS, "VEN first tpl data");
+ while (1) {
+ GOTO_ERROR_ON(tuple.TupleDataLen < 1, "VEN tpl < 1");
+ switch (tuple.TupleData[0]) {
+ case SSB_PCMCIA_CIS_ID:
+ GOTO_ERROR_ON((tuple.TupleDataLen != 5) &&
+ (tuple.TupleDataLen != 7),
+ "id tpl size");
+ bi->vendor = tuple.TupleData[1] |
+ ((u16)tuple.TupleData[2] << 8);
+ break;
+ case SSB_PCMCIA_CIS_BOARDREV:
+ GOTO_ERROR_ON(tuple.TupleDataLen != 2,
+ "boardrev tpl size");
+ sprom->board_rev = tuple.TupleData[1];
+ break;
+ case SSB_PCMCIA_CIS_PA:
+ GOTO_ERROR_ON(tuple.TupleDataLen != 9,
+ "pa tpl size");
+ sprom->pa0b0 = tuple.TupleData[1] |
+ ((u16)tuple.TupleData[2] << 8);
+ sprom->pa0b1 = tuple.TupleData[3] |
+ ((u16)tuple.TupleData[4] << 8);
+ sprom->pa0b2 = tuple.TupleData[5] |
+ ((u16)tuple.TupleData[6] << 8);
+ sprom->itssi_a = tuple.TupleData[7];
+ sprom->itssi_bg = tuple.TupleData[7];
+ sprom->maxpwr_a = tuple.TupleData[8];
+ sprom->maxpwr_bg = tuple.TupleData[8];
+ break;
+ case SSB_PCMCIA_CIS_OEMNAME:
+ /* We ignore this. */
+ break;
+ case SSB_PCMCIA_CIS_CCODE:
+ GOTO_ERROR_ON(tuple.TupleDataLen != 2,
+ "ccode tpl size");
+ sprom->country_code = tuple.TupleData[1];
+ break;
+ case SSB_PCMCIA_CIS_ANTENNA:
+ GOTO_ERROR_ON(tuple.TupleDataLen != 2,
+ "ant tpl size");
+ sprom->ant_available_a = tuple.TupleData[1];
+ sprom->ant_available_bg = tuple.TupleData[1];
+ break;
+ case SSB_PCMCIA_CIS_ANTGAIN:
+ GOTO_ERROR_ON(tuple.TupleDataLen != 2,
+ "antg tpl size");
+ sprom->antenna_gain.ghz24.a0 = tuple.TupleData[1];
+ sprom->antenna_gain.ghz24.a1 = tuple.TupleData[1];
+ sprom->antenna_gain.ghz24.a2 = tuple.TupleData[1];
+ sprom->antenna_gain.ghz24.a3 = tuple.TupleData[1];
+ sprom->antenna_gain.ghz5.a0 = tuple.TupleData[1];
+ sprom->antenna_gain.ghz5.a1 = tuple.TupleData[1];
+ sprom->antenna_gain.ghz5.a2 = tuple.TupleData[1];
+ sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1];
+ break;
+ case SSB_PCMCIA_CIS_BFLAGS:
+ GOTO_ERROR_ON(tuple.TupleDataLen != 3,
+ "bfl tpl size");
+ sprom->boardflags_lo = tuple.TupleData[1] |
+ ((u16)tuple.TupleData[2] << 8);
+ break;
+ case SSB_PCMCIA_CIS_LEDS:
+ GOTO_ERROR_ON(tuple.TupleDataLen != 5,
+ "leds tpl size");
+ sprom->gpio0 = tuple.TupleData[1];
+ sprom->gpio1 = tuple.TupleData[2];
+ sprom->gpio2 = tuple.TupleData[3];
+ sprom->gpio3 = tuple.TupleData[4];
+ break;
+ }
+ res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
+ if (res == CS_NO_MORE_ITEMS)
+ break;
+ GOTO_ERROR_ON(res != CS_SUCCESS, "VEN next tpl");
+ res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
+ GOTO_ERROR_ON(res != CS_SUCCESS, "VEN next tpl data");
+ }
+
return 0;
+error:
+ ssb_printk(KERN_ERR PFX
+ "PCMCIA: Failed to fetch device invariants: %s\n",
+ error_description);
+ return -ENODEV;
+}
+
+static ssize_t ssb_pcmcia_attr_sprom_show(struct device *pcmciadev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct pcmcia_device *pdev =
+ container_of(pcmciadev, struct pcmcia_device, dev);
+ struct ssb_bus *bus;
+
+ bus = ssb_pcmcia_dev_to_bus(pdev);
+ if (!bus)
+ return -ENODEV;
+
+ return ssb_attr_sprom_show(bus, buf,
+ ssb_pcmcia_sprom_read_all);
+}
+
+static ssize_t ssb_pcmcia_attr_sprom_store(struct device *pcmciadev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pcmcia_device *pdev =
+ container_of(pcmciadev, struct pcmcia_device, dev);
+ struct ssb_bus *bus;
+
+ bus = ssb_pcmcia_dev_to_bus(pdev);
+ if (!bus)
+ return -ENODEV;
+
+ return ssb_attr_sprom_store(bus, buf, count,
+ ssb_pcmcia_sprom_check_crc,
+ ssb_pcmcia_sprom_write_all);
+}
+
+static DEVICE_ATTR(ssb_sprom, 0600,
+ ssb_pcmcia_attr_sprom_show,
+ ssb_pcmcia_attr_sprom_store);
+
+void ssb_pcmcia_exit(struct ssb_bus *bus)
+{
+ if (bus->bustype != SSB_BUSTYPE_PCMCIA)
+ return;
+
+ device_remove_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom);
}
int ssb_pcmcia_init(struct ssb_bus *bus)
{
- conf_reg_t reg;
+ u8 val, offset;
int err;
if (bus->bustype != SSB_BUSTYPE_PCMCIA)
ssb_pcmcia_switch_segment(bus, 0);
/* Init IRQ routing */
- reg.Action = CS_READ;
- reg.Function = 0;
if (bus->chip_id == 0x4306)
- reg.Offset = 0x00;
+ offset = SSB_PCMCIA_CORECTL;
else
- reg.Offset = 0x80;
- err = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
- if (err != CS_SUCCESS)
+ offset = SSB_PCMCIA_CORECTL2;
+ err = ssb_pcmcia_cfg_read(bus, offset, &val);
+ if (err)
goto error;
- reg.Action = CS_WRITE;
- reg.Value |= 0x04 | 0x01;
- err = pcmcia_access_configuration_register(bus->host_pcmcia, ®);
- if (err != CS_SUCCESS)
+ val |= SSB_PCMCIA_CORECTL_IRQEN | SSB_PCMCIA_CORECTL_FUNCEN;
+ err = ssb_pcmcia_cfg_write(bus, offset, val);
+ if (err)
+ goto error;
+
+ bus->sprom_size = SSB_PCMCIA_SPROM_SIZE;
+ mutex_init(&bus->sprom_mutex);
+ err = device_create_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom);
+ if (err)
goto error;
return 0;
error:
- return -ENODEV;
+ ssb_printk(KERN_ERR PFX "Failed to initialize PCMCIA host device\n");
+ return err;
}
--- /dev/null
+/*
+ * Sonics Silicon Backplane
+ * Common SPROM support routines
+ *
+ * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "ssb_private.h"
+
+
+static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
+ size_t sprom_size_words)
+{
+ int i, pos = 0;
+
+ for (i = 0; i < sprom_size_words; i++)
+ pos += snprintf(buf + pos, buf_len - pos - 1,
+ "%04X", swab16(sprom[i]) & 0xFFFF);
+ pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
+
+ return pos + 1;
+}
+
+static int hex2sprom(u16 *sprom, const char *dump, size_t len,
+ size_t sprom_size_words)
+{
+ char tmp[5] = { 0 };
+ int cnt = 0;
+ unsigned long parsed;
+
+ if (len < sprom_size_words * 2)
+ return -EINVAL;
+
+ while (cnt < sprom_size_words) {
+ memcpy(tmp, dump, 4);
+ dump += 4;
+ parsed = simple_strtoul(tmp, NULL, 16);
+ sprom[cnt++] = swab16((u16)parsed);
+ }
+
+ return 0;
+}
+
+/* Common sprom device-attribute show-handler */
+ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf,
+ int (*sprom_read)(struct ssb_bus *bus, u16 *sprom))
+{
+ u16 *sprom;
+ int err = -ENOMEM;
+ ssize_t count = 0;
+ size_t sprom_size_words = bus->sprom_size;
+
+ sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL);
+ if (!sprom)
+ goto out;
+
+ /* Use interruptible locking, as the SPROM write might
+ * be holding the lock for several seconds. So allow userspace
+ * to cancel operation. */
+ err = -ERESTARTSYS;
+ if (mutex_lock_interruptible(&bus->sprom_mutex))
+ goto out_kfree;
+ err = sprom_read(bus, sprom);
+ mutex_unlock(&bus->sprom_mutex);
+
+ if (!err)
+ count = sprom2hex(sprom, buf, PAGE_SIZE, sprom_size_words);
+
+out_kfree:
+ kfree(sprom);
+out:
+ return err ? err : count;
+}
+
+/* Common sprom device-attribute store-handler */
+ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
+ const char *buf, size_t count,
+ int (*sprom_check_crc)(const u16 *sprom, size_t size),
+ int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom))
+{
+ u16 *sprom;
+ int res = 0, err = -ENOMEM;
+ size_t sprom_size_words = bus->sprom_size;
+
+ sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
+ if (!sprom)
+ goto out;
+ err = hex2sprom(sprom, buf, count, sprom_size_words);
+ if (err) {
+ err = -EINVAL;
+ goto out_kfree;
+ }
+ err = sprom_check_crc(sprom, sprom_size_words);
+ if (err) {
+ err = -EINVAL;
+ goto out_kfree;
+ }
+
+ /* Use interruptible locking, as the SPROM write might
+ * be holding the lock for several seconds. So allow userspace
+ * to cancel operation. */
+ err = -ERESTARTSYS;
+ if (mutex_lock_interruptible(&bus->sprom_mutex))
+ goto out_kfree;
+ err = ssb_devices_freeze(bus);
+ if (err == -EOPNOTSUPP) {
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
+ "No suspend support. Is CONFIG_PM enabled?\n");
+ goto out_unlock;
+ }
+ if (err) {
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
+ goto out_unlock;
+ }
+ res = sprom_write(bus, sprom);
+ err = ssb_devices_thaw(bus);
+ if (err)
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
+out_unlock:
+ mutex_unlock(&bus->sprom_mutex);
+out_kfree:
+ kfree(sprom);
+out:
+ if (res)
+ return res;
+ return err ? err : count;
+}
u8 seg);
extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv);
+extern void ssb_pcmcia_exit(struct ssb_bus *bus);
extern int ssb_pcmcia_init(struct ssb_bus *bus);
extern const struct ssb_bus_ops ssb_pcmcia_ops;
#else /* CONFIG_SSB_PCMCIAHOST */
{
return 0;
}
+static inline void ssb_pcmcia_exit(struct ssb_bus *bus)
+{
+}
static inline int ssb_pcmcia_init(struct ssb_bus *bus)
{
return 0;
extern void ssb_iounmap(struct ssb_bus *ssb);
+/* sprom.c */
+extern
+ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf,
+ int (*sprom_read)(struct ssb_bus *bus, u16 *sprom));
+extern
+ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
+ const char *buf, size_t count,
+ int (*sprom_check_crc)(const u16 *sprom, size_t size),
+ int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom));
+
+
/* core.c */
extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
extern int ssb_devices_freeze(struct ssb_bus *bus);
extern int ssb_devices_thaw(struct ssb_bus *bus);
extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
+int ssb_for_each_bus_call(unsigned long data,
+ int (*func)(struct ssb_bus *bus, unsigned long data));
+extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev);
+
/* b43_pci_bridge.c */
#ifdef CONFIG_SSB_B43_PCI_BRIDGE
__u32 info,
struct net_device *dev);
-extern int icmpv6_init(struct net_proto_family *ops);
+extern int icmpv6_init(void);
extern int icmpv6_err_convert(int type, int code,
int *err);
extern void icmpv6_cleanup(void);
extern void icmpv6_param_prob(struct sk_buff *skb,
int code, int pos);
+
+struct flowi;
+struct in6_addr;
+extern void icmpv6_flow_init(struct sock *sk,
+ struct flowi *fl,
+ u8 type,
+ const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
+ int oif);
#endif
#endif
#define IEEE80211_MAX_FRAME_LEN 2352
#define IEEE80211_MAX_SSID_LEN 32
+#define IEEE80211_MAX_MESH_ID_LEN 32
struct ieee80211_hdr {
__le16 frame_control;
} __attribute__ ((packed));
+struct ieee80211s_hdr {
+ u8 flags;
+ u8 ttl;
+ u8 seqnum[3];
+ u8 eaddr1[6];
+ u8 eaddr2[6];
+ u8 eaddr3[6];
+} __attribute__ ((packed));
+
+
struct ieee80211_mgmt {
__le16 frame_control;
__le16 duration;
__le16 params;
__le16 reason_code;
} __attribute__((packed)) delba;
+ struct{
+ u8 action_code;
+ /* capab_info for open and confirm,
+ * reason for close
+ */
+ __le16 aux;
+ /* Followed in plink_confirm by status
+ * code, AID and supported rates,
+ * and directly by supported rates in
+ * plink_open and plink_close
+ */
+ u8 variable[0];
+ } __attribute__((packed)) plink_action;
+ struct{
+ u8 action_code;
+ u8 variable[0];
+ } __attribute__((packed)) mesh_action;
} u;
} __attribute__ ((packed)) action;
} u;
WLAN_EID_TS_DELAY = 43,
WLAN_EID_TCLAS_PROCESSING = 44,
WLAN_EID_QOS_CAPA = 46,
+ /* 802.11s */
+ WLAN_EID_MESH_CONFIG = 36, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_MESH_ID = 37, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_PEER_LINK = 40, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_PREQ = 53, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_PREP = 54, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_PERR = 55, /* Pending IEEE 802.11 ANA approval */
/* 802.11h */
WLAN_EID_PWR_CONSTRAINT = 32,
WLAN_EID_PWR_CAPABILITY = 33,
{
return (struct arphdr *)skb_network_header(skb);
}
+
+static inline int arp_hdr_len(struct net_device *dev)
+{
+ /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
+ return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2;
+}
#endif
#endif /* _LINUX_IF_ARP_H */
extern struct net_device *ip_dev_find(struct net *net, __be32 addr);
extern int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b);
-extern int devinet_ioctl(unsigned int cmd, void __user *);
+extern int devinet_ioctl(struct net *net, unsigned int cmd, void __user *);
extern void devinet_init(void);
extern struct in_device *inetdev_by_index(struct net *, int);
extern __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope);
* or, if no MAC address given, all stations, on the interface identified
* by %NL80211_ATTR_IFINDEX.
*
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all mesh paths, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
/* add commands here */
+ NL80211_CMD_GET_MPATH,
+ NL80211_CMD_SET_MPATH,
+ NL80211_CMD_NEW_MPATH,
+ NL80211_CMD_DEL_MPATH,
+
/* used to define NL80211_CMD_MAX below */
__NL80211_CMD_AFTER_LAST,
NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
* restriction (at most %NL80211_MAX_SUPP_RATES).
* @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
* to, or the AP interface the station was originally added to to.
- * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
* given for %NL80211_CMD_GET_STATION, nested attribute containing
- * info as possible, see &enum nl80211_sta_stats.
+ * info as possible, see &enum nl80211_sta_info.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ * consisting of a nested array.
+ *
+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
+ * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
+ * info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ * &enum nl80211_mpath_info.
+ *
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_mntr_flags.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
NL80211_ATTR_STA_LISTEN_INTERVAL,
NL80211_ATTR_STA_SUPPORTED_RATES,
NL80211_ATTR_STA_VLAN,
- NL80211_ATTR_STA_STATS,
+ NL80211_ATTR_STA_INFO,
+
+ NL80211_ATTR_WIPHY_BANDS,
+
+ NL80211_ATTR_MNTR_FLAGS,
/* add attributes here, update the policy in nl80211.c */
+ NL80211_ATTR_MESH_ID,
+ NL80211_ATTR_STA_PLINK_ACTION,
+ NL80211_ATTR_MPATH_NEXT_HOP,
+ NL80211_ATTR_MPATH_INFO,
+
__NL80211_ATTR_AFTER_LAST,
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};
* @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
* @NL80211_IFTYPE_WDS: wireless distribution interface
* @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @__NL80211_IFTYPE_AFTER_LAST: internal use
*
NL80211_IFTYPE_AP_VLAN,
NL80211_IFTYPE_WDS,
NL80211_IFTYPE_MONITOR,
+ NL80211_IFTYPE_MESH_POINT,
/* keep last */
__NL80211_IFTYPE_AFTER_LAST,
};
/**
- * enum nl80211_sta_stats - station statistics
+ * enum nl80211_sta_info - station information
*
- * These attribute types are used with %NL80211_ATTR_STA_STATS
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
* when getting information about a station.
*
- * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
- * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
- * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
- * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_STAT_AFTER_LAST: internal
- * @NL80211_STA_STAT_MAX: highest possible station stats attribute
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ */
+enum nl80211_sta_info {
+ __NL80211_STA_INFO_INVALID,
+ NL80211_STA_INFO_INACTIVE_TIME,
+ NL80211_STA_INFO_RX_BYTES,
+ NL80211_STA_INFO_TX_BYTES,
+ NL80211_STA_INFO_LLID,
+ NL80211_STA_INFO_PLID,
+ NL80211_STA_INFO_PLINK_STATE,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+ NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+ NL80211_MPATH_FLAG_ACTIVE = 1<<0,
+ NL80211_MPATH_FLAG_RESOLVING = 1<<1,
+ NL80211_MPATH_FLAG_DSN_VALID = 1<<2,
+ NL80211_MPATH_FLAG_FIXED = 1<<3,
+ NL80211_MPATH_FLAG_RESOLVED = 1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_ATTR_MPATH_DSN: destination sequence number
+ * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
+ * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * &enum nl80211_mpath_flags;
+ * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ */
+enum nl80211_mpath_info {
+ __NL80211_MPATH_INFO_INVALID,
+ NL80211_MPATH_INFO_FRAME_QLEN,
+ NL80211_MPATH_INFO_DSN,
+ NL80211_MPATH_INFO_METRIC,
+ NL80211_MPATH_INFO_EXPTIME,
+ NL80211_MPATH_INFO_FLAGS,
+ NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+
+ /* keep last */
+ __NL80211_MPATH_INFO_AFTER_LAST,
+ NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ * an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ * an array of nested bitrate attributes
+ */
+enum nl80211_band_attr {
+ __NL80211_BAND_ATTR_INVALID,
+ NL80211_BAND_ATTR_FREQS,
+ NL80211_BAND_ATTR_RATES,
+
+ /* keep last */
+ __NL80211_BAND_ATTR_AFTER_LAST,
+ NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ * regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ * permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ * on this channel in current regulatory domain.
+ */
+enum nl80211_frequency_attr {
+ __NL80211_FREQUENCY_ATTR_INVALID,
+ NL80211_FREQUENCY_ATTR_FREQ,
+ NL80211_FREQUENCY_ATTR_DISABLED,
+ NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+ NL80211_FREQUENCY_ATTR_NO_IBSS,
+ NL80211_FREQUENCY_ATTR_RADAR,
+
+ /* keep last */
+ __NL80211_FREQUENCY_ATTR_AFTER_LAST,
+ NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ * in 2.4 GHz band.
+ */
+enum nl80211_bitrate_attr {
+ __NL80211_BITRATE_ATTR_INVALID,
+ NL80211_BITRATE_ATTR_RATE,
+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+ /* keep last */
+ __NL80211_BITRATE_ATTR_AFTER_LAST,
+ NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ * overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
*/
-enum nl80211_sta_stats {
- __NL80211_STA_STAT_INVALID,
- NL80211_STA_STAT_INACTIVE_TIME,
- NL80211_STA_STAT_RX_BYTES,
- NL80211_STA_STAT_TX_BYTES,
+enum nl80211_mntr_flags {
+ __NL80211_MNTR_FLAG_INVALID,
+ NL80211_MNTR_FLAG_FCSFAIL,
+ NL80211_MNTR_FLAG_PLCPFAIL,
+ NL80211_MNTR_FLAG_CONTROL,
+ NL80211_MNTR_FLAG_OTHER_BSS,
+ NL80211_MNTR_FLAG_COOK_FRAMES,
/* keep last */
- __NL80211_STA_STAT_AFTER_LAST,
- NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
+ __NL80211_MNTR_FLAG_AFTER_LAST,
+ NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
};
#endif /* __LINUX_NL80211_H */
ktime_t tstamp;
struct net_device *dev;
- struct dst_entry *dst;
+ union {
+ struct dst_entry *dst;
+ struct rtable *rtable;
+ };
struct sec_path *sp;
/*
/* Lowlevel read/write operations on the device MMIO.
* Internal, don't use that outside of ssb. */
struct ssb_bus_ops {
+ u8 (*read8)(struct ssb_device *dev, u16 offset);
u16 (*read16)(struct ssb_device *dev, u16 offset);
u32 (*read32)(struct ssb_device *dev, u16 offset);
+ void (*write8)(struct ssb_device *dev, u16 offset, u8 value);
void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
};
/* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */
struct pcmcia_device *host_pcmcia;
-#ifdef CONFIG_SSB_PCIHOST
+#ifdef CONFIG_SSB_SPROM
/* Mutex to protect the SPROM writing. */
- struct mutex pci_sprom_mutex;
+ struct mutex sprom_mutex;
#endif
/* ID information about the Chip. */
/* Device MMIO register read/write functions. */
+static inline u8 ssb_read8(struct ssb_device *dev, u16 offset)
+{
+ return dev->ops->read8(dev, offset);
+}
static inline u16 ssb_read16(struct ssb_device *dev, u16 offset)
{
return dev->ops->read16(dev, offset);
{
return dev->ops->read32(dev, offset);
}
+static inline void ssb_write8(struct ssb_device *dev, u16 offset, u8 value)
+{
+ dev->ops->write8(dev, offset, value);
+}
static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
{
dev->ops->write16(dev, offset, value);
extern u32 ssb_admatch_base(u32 adm);
extern u32 ssb_admatch_size(u32 adm);
+/* PCI device mapping and fixup routines.
+ * Called from the architecture pcibios init code.
+ * These are only available on SSB_EMBEDDED configurations. */
+#ifdef CONFIG_SSB_EMBEDDED
+int ssb_pcibios_plat_dev_init(struct pci_dev *dev);
+int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
+#endif /* CONFIG_SSB_EMBEDDED */
#endif /* LINUX_SSB_H_ */
extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc,
u32 ticks);
+void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value);
+
+u32 ssb_chipco_irq_status(struct ssb_chipcommon *cc, u32 mask);
+
/* Chipcommon GPIO pin access. */
u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask);
u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value);
--- /dev/null
+#ifndef LINUX_SSB_DRIVER_GIGE_H_
+#define LINUX_SSB_DRIVER_GIGE_H_
+
+#include <linux/ssb/ssb.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+
+#ifdef CONFIG_SSB_DRIVER_GIGE
+
+
+#define SSB_GIGE_PCIIO 0x0000 /* PCI I/O Registers (1024 bytes) */
+#define SSB_GIGE_RESERVED 0x0400 /* Reserved (1024 bytes) */
+#define SSB_GIGE_PCICFG 0x0800 /* PCI config space (256 bytes) */
+#define SSB_GIGE_SHIM_FLUSHSTAT 0x0C00 /* PCI to OCP: Flush status control (32bit) */
+#define SSB_GIGE_SHIM_FLUSHRDA 0x0C04 /* PCI to OCP: Flush read address (32bit) */
+#define SSB_GIGE_SHIM_FLUSHTO 0x0C08 /* PCI to OCP: Flush timeout counter (32bit) */
+#define SSB_GIGE_SHIM_BARRIER 0x0C0C /* PCI to OCP: Barrier register (32bit) */
+#define SSB_GIGE_SHIM_MAOCPSI 0x0C10 /* PCI to OCP: MaocpSI Control (32bit) */
+#define SSB_GIGE_SHIM_SIOCPMA 0x0C14 /* PCI to OCP: SiocpMa Control (32bit) */
+
+/* TM Status High flags */
+#define SSB_GIGE_TMSHIGH_RGMII 0x00010000 /* Have an RGMII PHY-bus */
+/* TM Status Low flags */
+#define SSB_GIGE_TMSLOW_TXBYPASS 0x00080000 /* TX bypass (no delay) */
+#define SSB_GIGE_TMSLOW_RXBYPASS 0x00100000 /* RX bypass (no delay) */
+#define SSB_GIGE_TMSLOW_DLLEN 0x01000000 /* Enable DLL controls */
+
+/* Boardflags (low) */
+#define SSB_GIGE_BFL_ROBOSWITCH 0x0010
+
+
+#define SSB_GIGE_MEM_RES_NAME "SSB Broadcom 47xx GigE memory"
+#define SSB_GIGE_IO_RES_NAME "SSB Broadcom 47xx GigE I/O"
+
+struct ssb_gige {
+ struct ssb_device *dev;
+
+ spinlock_t lock;
+
+ /* True, if the device has an RGMII bus.
+ * False, if the device has a GMII bus. */
+ bool has_rgmii;
+
+ /* The PCI controller device. */
+ struct pci_controller pci_controller;
+ struct pci_ops pci_ops;
+ struct resource mem_resource;
+ struct resource io_resource;
+};
+
+/* Check whether a PCI device is a SSB Gigabit Ethernet core. */
+extern bool pdev_is_ssb_gige_core(struct pci_dev *pdev);
+
+/* Convert a pci_dev pointer to a ssb_gige pointer. */
+static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev)
+{
+ if (!pdev_is_ssb_gige_core(pdev))
+ return NULL;
+ return container_of(pdev->bus->ops, struct ssb_gige, pci_ops);
+}
+
+/* Returns whether the PHY is connected by an RGMII bus. */
+static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev)
+{
+ struct ssb_gige *dev = pdev_to_ssb_gige(pdev);
+ return (dev ? dev->has_rgmii : 0);
+}
+
+/* Returns whether we have a Roboswitch. */
+static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev)
+{
+ struct ssb_gige *dev = pdev_to_ssb_gige(pdev);
+ if (dev)
+ return !!(dev->dev->bus->sprom.boardflags_lo &
+ SSB_GIGE_BFL_ROBOSWITCH);
+ return 0;
+}
+
+/* Returns whether we can only do one DMA at once. */
+static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev)
+{
+ struct ssb_gige *dev = pdev_to_ssb_gige(pdev);
+ if (dev)
+ return ((dev->dev->bus->chip_id == 0x4785) &&
+ (dev->dev->bus->chip_rev < 2));
+ return 0;
+}
+
+/* Returns whether we must flush posted writes. */
+static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev)
+{
+ struct ssb_gige *dev = pdev_to_ssb_gige(pdev);
+ if (dev)
+ return (dev->dev->bus->chip_id == 0x4785);
+ return 0;
+}
+
+extern char * nvram_get(const char *name);
+/* Get the device MAC address */
+static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
+{
+#ifdef CONFIG_BCM947XX
+ char *res = nvram_get("et0macaddr");
+ if (res)
+ memcpy(macaddr, res, 6);
+#endif
+}
+
+extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
+ struct pci_dev *pdev);
+extern int ssb_gige_map_irq(struct ssb_device *sdev,
+ const struct pci_dev *pdev);
+
+/* The GigE driver is not a standalone module, because we don't have support
+ * for unregistering the driver. So we could not unload the module anyway. */
+extern int ssb_gige_init(void);
+static inline void ssb_gige_exit(void)
+{
+ /* Currently we can not unregister the GigE driver,
+ * because we can not unregister the PCI bridge. */
+ BUG();
+}
+
+
+#else /* CONFIG_SSB_DRIVER_GIGE */
+/* Gigabit Ethernet driver disabled */
+
+
+static inline int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
+ struct pci_dev *pdev)
+{
+ return -ENOSYS;
+}
+static inline int ssb_gige_map_irq(struct ssb_device *sdev,
+ const struct pci_dev *pdev)
+{
+ return -ENOSYS;
+}
+static inline int ssb_gige_init(void)
+{
+ return 0;
+}
+static inline void ssb_gige_exit(void)
+{
+}
+
+static inline bool pdev_is_ssb_gige_core(struct pci_dev *pdev)
+{
+ return 0;
+}
+static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev)
+{
+ return NULL;
+}
+static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev)
+{
+ return 0;
+}
+static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev)
+{
+ return 0;
+}
+static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev)
+{
+ return 0;
+}
+static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev)
+{
+ return 0;
+}
+
+#endif /* CONFIG_SSB_DRIVER_GIGE */
+#endif /* LINUX_SSB_DRIVER_GIGE_H_ */
#ifndef LINUX_SSB_PCICORE_H_
#define LINUX_SSB_PCICORE_H_
+#include <linux/types.h>
+
+struct pci_dev;
+
+
#ifdef CONFIG_SSB_DRIVER_PCICORE
/* PCI core registers. */
extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
struct ssb_device *dev);
+int ssb_pcicore_plat_dev_init(struct pci_dev *d);
+int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
+
#else /* CONFIG_SSB_DRIVER_PCICORE */
return 0;
}
+static inline
+int ssb_pcicore_plat_dev_init(struct pci_dev *d)
+{
+ return -ENODEV;
+}
+static inline
+int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_SSB_DRIVER_PCICORE */
#endif /* LINUX_SSB_PCICORE_H_ */
{
return (struct udp_sock *)sk;
}
+
#define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag)
#endif
#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */
#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
+#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */
/* Statistics flags (bitmask in updated) */
#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */
{
XFRM_POLICY_TYPE_MAIN = 0,
XFRM_POLICY_TYPE_SUB = 1,
- XFRM_POLICY_TYPE_MAX = 2
+ XFRM_POLICY_TYPE_MAX = 2,
+ XFRM_POLICY_TYPE_ANY = 255
};
enum
extern int addrconf_init(void);
extern void addrconf_cleanup(void);
-extern int addrconf_add_ifaddr(void __user *arg);
-extern int addrconf_del_ifaddr(void __user *arg);
-extern int addrconf_set_dstaddr(void __user *arg);
+extern int addrconf_add_ifaddr(struct net *net,
+ void __user *arg);
+extern int addrconf_del_ifaddr(struct net *net,
+ void __user *arg);
+extern int addrconf_set_dstaddr(struct net *net,
+ void __user *arg);
extern int ipv6_chk_addr(struct net *net,
struct in6_addr *addr,
struct net_device *dev,
int strict);
-extern int ipv6_get_saddr(struct dst_entry *dst,
- struct in6_addr *daddr,
- struct in6_addr *saddr);
extern int ipv6_dev_get_saddr(struct net_device *dev,
struct in6_addr *daddr,
struct in6_addr *saddr);
struct in6_addr *solicited)
{
ipv6_addr_set(solicited,
- __constant_htonl(0xFF020000), 0,
- __constant_htonl(0x1),
- __constant_htonl(0xFF000000) | addr->s6_addr32[3]);
+ htonl(0xFF020000), 0,
+ htonl(0x1),
+ htonl(0xFF000000) | addr->s6_addr32[3]);
}
static inline void ipv6_addr_all_nodes(struct in6_addr *addr)
{
- ipv6_addr_set(addr,
- __constant_htonl(0xFF020000), 0, 0,
- __constant_htonl(0x1));
+ ipv6_addr_set(addr, htonl(0xFF020000), 0, 0, htonl(0x1));
}
static inline void ipv6_addr_all_routers(struct in6_addr *addr)
{
- ipv6_addr_set(addr,
- __constant_htonl(0xFF020000), 0, 0,
- __constant_htonl(0x2));
+ ipv6_addr_set(addr, htonl(0xFF020000), 0, 0, htonl(0x2));
}
static inline int ipv6_addr_is_multicast(const struct in6_addr *addr)
{
- return (addr->s6_addr32[0] & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000);
+ return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000);
}
static inline int ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*/
+/**
+ * struct vif_params - describes virtual interface parameters
+ * @mesh_id: mesh ID to use
+ * @mesh_id_len: length of the mesh ID
+ */
+struct vif_params {
+ u8 *mesh_id;
+ int mesh_id_len;
+};
+
/* Radiotap header iteration
* implemented in net/wireless/radiotap.c
* docs in Documentation/networking/radiotap-headers.txt
};
/**
+ * enum plink_action - actions to perform in mesh peers
+ *
+ * @PLINK_ACTION_INVALID: action 0 is reserved
+ * @PLINK_ACTION_OPEN: start mesh peer link establishment
+ * @PLINK_ACTION_BLOCL: block traffic from this mesh peer
+ */
+enum plink_actions {
+ PLINK_ACTION_INVALID,
+ PLINK_ACTION_OPEN,
+ PLINK_ACTION_BLOCK,
+};
+
+/**
* struct station_parameters - station parameters
*
* Used to change and create a new station.
int listen_interval;
u16 aid;
u8 supported_rates_len;
+ u8 plink_action;
};
/**
- * enum station_stats_flags - station statistics flags
+ * enum station_info_flags - station information flags
*
- * Used by the driver to indicate which info in &struct station_stats
- * it has filled in during get_station().
+ * Used by the driver to indicate which info in &struct station_info
+ * it has filled in during get_station() or dump_station().
*
- * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
- * @STATION_STAT_RX_BYTES: @rx_bytes filled
- * @STATION_STAT_TX_BYTES: @tx_bytes filled
+ * @STATION_INFO_INACTIVE_TIME: @inactive_time filled
+ * @STATION_INFO_RX_BYTES: @rx_bytes filled
+ * @STATION_INFO_TX_BYTES: @tx_bytes filled
+ * @STATION_INFO_LLID: @llid filled
+ * @STATION_INFO_PLID: @plid filled
+ * @STATION_INFO_PLINK_STATE: @plink_state filled
*/
-enum station_stats_flags {
- STATION_STAT_INACTIVE_TIME = 1<<0,
- STATION_STAT_RX_BYTES = 1<<1,
- STATION_STAT_TX_BYTES = 1<<2,
+enum station_info_flags {
+ STATION_INFO_INACTIVE_TIME = 1<<0,
+ STATION_INFO_RX_BYTES = 1<<1,
+ STATION_INFO_TX_BYTES = 1<<2,
+ STATION_INFO_LLID = 1<<3,
+ STATION_INFO_PLID = 1<<4,
+ STATION_INFO_PLINK_STATE = 1<<5,
};
/**
- * struct station_stats - station statistics
+ * struct station_info - station information
*
- * Station information filled by driver for get_station().
+ * Station information filled by driver for get_station() and dump_station.
*
- * @filled: bitflag of flags from &enum station_stats_flags
+ * @filled: bitflag of flags from &enum station_info_flags
* @inactive_time: time since last station activity (tx/rx) in milliseconds
* @rx_bytes: bytes received from this station
* @tx_bytes: bytes transmitted to this station
+ * @llid: mesh local link id
+ * @plid: mesh peer link id
+ * @plink_state: mesh peer link state
*/
-struct station_stats {
+struct station_info {
u32 filled;
u32 inactive_time;
u32 rx_bytes;
u32 tx_bytes;
+ u16 llid;
+ u16 plid;
+ u8 plink_state;
+};
+
+/**
+ * enum monitor_flags - monitor flags
+ *
+ * Monitor interface configuration flags. Note that these must be the bits
+ * according to the nl80211 flags.
+ *
+ * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @MONITOR_FLAG_CONTROL: pass control frames
+ * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @MONITOR_FLAG_COOK_FRAMES: report frames after processing
+ */
+enum monitor_flags {
+ MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL,
+ MONITOR_FLAG_PLCPFAIL = 1<<NL80211_MNTR_FLAG_PLCPFAIL,
+ MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL,
+ MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
+ MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
};
+/**
+ * enum mpath_info_flags - mesh path information flags
+ *
+ * Used by the driver to indicate which info in &struct mpath_info it has filled
+ * in during get_station() or dump_station().
+ *
+ * MPATH_INFO_FRAME_QLEN: @frame_qlen filled
+ * MPATH_INFO_DSN: @dsn filled
+ * MPATH_INFO_METRIC: @metric filled
+ * MPATH_INFO_EXPTIME: @exptime filled
+ * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled
+ * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled
+ * MPATH_INFO_FLAGS: @flags filled
+ */
+enum mpath_info_flags {
+ MPATH_INFO_FRAME_QLEN = BIT(0),
+ MPATH_INFO_DSN = BIT(1),
+ MPATH_INFO_METRIC = BIT(2),
+ MPATH_INFO_EXPTIME = BIT(3),
+ MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4),
+ MPATH_INFO_DISCOVERY_RETRIES = BIT(5),
+ MPATH_INFO_FLAGS = BIT(6),
+};
+
+/**
+ * struct mpath_info - mesh path information
+ *
+ * Mesh path information filled by driver for get_mpath() and dump_mpath().
+ *
+ * @filled: bitfield of flags from &enum mpath_info_flags
+ * @frame_qlen: number of queued frames for this destination
+ * @dsn: destination sequence number
+ * @metric: metric (cost) of this mesh path
+ * @exptime: expiration time for the mesh path from now, in msecs
+ * @flags: mesh path flags
+ * @discovery_timeout: total mesh path discovery timeout, in msecs
+ * @discovery_retries: mesh path discovery retries
+ */
+struct mpath_info {
+ u32 filled;
+ u32 frame_qlen;
+ u32 dsn;
+ u32 metric;
+ u32 exptime;
+ u32 discovery_timeout;
+ u8 discovery_retries;
+ u8 flags;
+};
+
+
/* from net/wireless.h */
struct wiphy;
* @del_station: Remove a station; @mac may be NULL to remove all stations.
*
* @change_station: Modify a given station.
+ *
+ * @set_mesh_cfg: set mesh parameters (by now, just mesh id)
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
- enum nl80211_iftype type);
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params);
int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
- enum nl80211_iftype type);
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params);
int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, u8 *mac_addr,
int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_parameters *params);
int (*get_station)(struct wiphy *wiphy, struct net_device *dev,
- u8 *mac, struct station_stats *stats);
+ u8 *mac, struct station_info *sinfo);
+ int (*dump_station)(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *mac, struct station_info *sinfo);
+
+ int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop);
+ int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst);
+ int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop);
+ int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo);
+ int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo);
};
#endif /* __NET_CFG80211_H */
extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info);
extern int icmp_rcv(struct sk_buff *skb);
extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
-extern void icmp_init(struct net_proto_family *ops);
+extern int icmp_init(void);
extern void icmp_out_count(unsigned char type);
/* Move into dst.h ? */
#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a)
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <linux/if_arp.h> /* ARPHRD_ETHER */
#ifndef WIRELESS_SPY
+++ /dev/null
-/*
- * ieee80211softmac.h - public interface to the softmac
- *
- * Copyright (c) 2005 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#ifndef IEEE80211SOFTMAC_H_
-#define IEEE80211SOFTMAC_H_
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/list.h>
-#include <net/ieee80211.h>
-
-/* Once the API is considered more or less stable,
- * this should be incremented on API incompatible changes.
- */
-#define IEEE80211SOFTMAC_API 0
-
-#define IEEE80211SOFTMAC_MAX_RATES_LEN 8
-#define IEEE80211SOFTMAC_MAX_EX_RATES_LEN 255
-
-struct ieee80211softmac_ratesinfo {
- u8 count;
- u8 rates[IEEE80211SOFTMAC_MAX_RATES_LEN + IEEE80211SOFTMAC_MAX_EX_RATES_LEN];
-};
-
-/* internal structures */
-struct ieee80211softmac_network;
-struct ieee80211softmac_scaninfo;
-
-struct ieee80211softmac_essid {
- u8 len;
- char data[IW_ESSID_MAX_SIZE+1];
-};
-
-struct ieee80211softmac_wpa {
- char *IE;
- int IElen;
- int IEbuflen;
-};
-
-/*
- * Information about association
- */
-struct ieee80211softmac_assoc_info {
-
- struct mutex mutex;
-
- /*
- * This is the requested ESSID. It is written
- * only by the WX handlers.
- *
- */
- struct ieee80211softmac_essid req_essid;
- /*
- * the ESSID of the network we're currently
- * associated (or trying) to. This is
- * updated to the network's actual ESSID
- * even if the requested ESSID was 'ANY'
- */
- struct ieee80211softmac_essid associate_essid;
-
- /* BSSID we're trying to associate to */
- char bssid[ETH_ALEN];
-
- /* some flags.
- * static_essid is valid if the essid is constant,
- * this is for use by the wx handlers only.
- *
- * associating is true, if the network has been
- * auth'ed on and we are in the process of associating.
- *
- * bssvalid is true if we found a matching network
- * and saved it's BSSID into the bssid above.
- *
- * bssfixed is used for SIOCSIWAP.
- */
- u8 static_essid;
- u8 short_preamble_available;
- u8 associating;
- u8 associated;
- u8 assoc_wait;
- u8 bssvalid;
- u8 bssfixed;
-
- /* Scan retries remaining */
- int scan_retry;
-
- struct delayed_work work;
- struct delayed_work timeout;
-};
-
-struct ieee80211softmac_bss_info {
- /* Rates supported by the network */
- struct ieee80211softmac_ratesinfo supported_rates;
-
- /* This indicates whether frames can currently be transmitted with
- * short preamble (only use this variable during TX at CCK rates) */
- u8 short_preamble:1;
-
- /* This indicates whether protection (e.g. self-CTS) should be used
- * when transmitting with OFDM modulation */
- u8 use_protection:1;
-};
-
-enum {
- IEEE80211SOFTMAC_AUTH_OPEN_REQUEST = 1,
- IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE = 2,
-};
-
-enum {
- IEEE80211SOFTMAC_AUTH_SHARED_REQUEST = 1,
- IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE = 2,
- IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE = 3,
- IEEE80211SOFTMAC_AUTH_SHARED_PASS = 4,
-};
-
-/* We should make these tunable
- * AUTH_TIMEOUT seems really long, but that's what it is in BSD */
-#define IEEE80211SOFTMAC_AUTH_TIMEOUT (12 * HZ)
-#define IEEE80211SOFTMAC_AUTH_RETRY_LIMIT 5
-#define IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT 3
-
-struct ieee80211softmac_txrates {
- /* The Bit-Rate to be used for multicast frames. */
- u8 mcast_rate;
-
- /* The Bit-Rate to be used for multicast management frames. */
- u8 mgt_mcast_rate;
-
- /* The Bit-Rate to be used for any other (normal) data packet. */
- u8 default_rate;
- /* The Bit-Rate to be used for default fallback
- * (If the device supports fallback and hardware-retry)
- */
- u8 default_fallback;
-
- /* This is the rate that the user asked for */
- u8 user_rate;
-};
-
-/* Bits for txrates_change callback. */
-#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT (1 << 0) /* default_rate */
-#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK (1 << 1) /* default_fallback */
-#define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */
-#define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 3) /* mgt_mcast_rate */
-
-#define IEEE80211SOFTMAC_BSSINFOCHG_RATES (1 << 0) /* supported_rates */
-#define IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE (1 << 1) /* short_preamble */
-#define IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION (1 << 2) /* use_protection */
-
-struct ieee80211softmac_device {
- /* 802.11 structure for data stuff */
- struct ieee80211_device *ieee;
- struct net_device *dev;
-
- /* only valid if associated, then holds the Association ID */
- u16 association_id;
-
- /* the following methods are callbacks that the driver
- * using this framework has to assign
- */
-
- /* always assign these */
- void (*set_bssid_filter)(struct net_device *dev, const u8 *bssid);
- void (*set_channel)(struct net_device *dev, u8 channel);
-
- /* assign if you need it, informational only */
- void (*link_change)(struct net_device *dev);
-
- /* If the hardware can do scanning, assign _all_ three of these callbacks.
- * When the scan finishes, call ieee80211softmac_scan_finished().
- */
-
- /* when called, start_scan is guaranteed to not be called again
- * until you call ieee80211softmac_scan_finished.
- * Return 0 if scanning could start, error otherwise.
- * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_start_scan */
- int (*start_scan)(struct net_device *dev);
- /* this should block until after ieee80211softmac_scan_finished was called
- * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_wait_for_scan */
- void (*wait_for_scan)(struct net_device *dev);
- /* stop_scan aborts a scan, but is asynchronous.
- * if you want to wait for it too, use wait_for_scan
- * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_stop_scan */
- void (*stop_scan)(struct net_device *dev);
-
- /* we'll need something about beacons here too, for AP or ad-hoc modes */
-
- /* Transmission rates to be used by the driver.
- * The SoftMAC figures out the best possible rates.
- * The driver just needs to read them.
- */
- struct ieee80211softmac_txrates txrates;
-
- /* If the driver needs to do stuff on TX rate changes, assign this
- * callback. See IEEE80211SOFTMAC_TXRATECHG for change flags. */
- void (*txrates_change)(struct net_device *dev,
- u32 changes);
-
- /* If the driver needs to do stuff when BSS properties change, assign
- * this callback. see IEEE80211SOFTMAC_BSSINFOCHG for change flags. */
- void (*bssinfo_change)(struct net_device *dev,
- u32 changes);
-
- /* private stuff follows */
- /* this lock protects this structure */
- spinlock_t lock;
-
- struct workqueue_struct *wq;
-
- u8 running; /* SoftMAC started? */
- u8 scanning;
-
- struct ieee80211softmac_scaninfo *scaninfo;
- struct ieee80211softmac_assoc_info associnfo;
- struct ieee80211softmac_bss_info bssinfo;
-
- struct list_head auth_queue;
- struct list_head events;
-
- struct ieee80211softmac_ratesinfo ratesinfo;
- int txrate_badness;
-
- /* WPA stuff */
- struct ieee80211softmac_wpa wpa;
-
- /* we need to keep a list of network structs we copied */
- struct list_head network_list;
-
- /* This must be the last item so that it points to the data
- * allocated beyond this structure by alloc_ieee80211 */
- u8 priv[0];
-};
-
-extern void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm);
-
-static inline void * ieee80211softmac_priv(struct net_device *dev)
-{
- return ((struct ieee80211softmac_device *)ieee80211_priv(dev))->priv;
-}
-
-extern struct net_device * alloc_ieee80211softmac(int sizeof_priv);
-extern void free_ieee80211softmac(struct net_device *dev);
-
-/* Call this function if you detect a lost TX fragment.
- * (If the device indicates failure of ACK RX, for example.)
- * It is wise to call this function if you are able to detect lost packets,
- * because it contributes to the TX Rates auto adjustment.
- */
-extern void ieee80211softmac_fragment_lost(struct net_device *dev,
- u16 wireless_sequence_number);
-/* Call this function before _start to tell the softmac what rates
- * the hw supports. The rates parameter is copied, so you can
- * free it right after calling this function.
- * Note that the rates need to be sorted. */
-extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
-
-/* Finds the highest rate which is:
- * 1. Present in ri (optionally a basic rate)
- * 2. Supported by the device
- * 3. Less than or equal to the user-defined rate
- */
-extern u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_ratesinfo *ri, int basic_only);
-
-/* Helper function which advises you the rate at which a frame should be
- * transmitted at. */
-static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac,
- int is_multicast,
- int is_mgt)
-{
- struct ieee80211softmac_txrates *txrates = &mac->txrates;
-
- if (!mac->associnfo.associated)
- return txrates->mgt_mcast_rate;
-
- /* We are associated, sending unicast frame */
- if (!is_multicast)
- return txrates->default_rate;
-
- /* We are associated, sending multicast frame */
- if (is_mgt)
- return txrates->mgt_mcast_rate;
- else
- return txrates->mcast_rate;
-}
-
-/* Helper function which advises you when it is safe to transmit with short
- * preamble.
- * You should only call this function when transmitting at CCK rates. */
-static inline int ieee80211softmac_short_preamble_ok(struct ieee80211softmac_device *mac,
- int is_multicast,
- int is_mgt)
-{
- return (is_multicast && is_mgt) ? 0 : mac->bssinfo.short_preamble;
-}
-
-/* Helper function which advises you whether protection (e.g. self-CTS) is
- * needed. 1 = protection needed, 0 = no protection needed
- * Only use this function when transmitting with OFDM modulation. */
-static inline int ieee80211softmac_protection_needed(struct ieee80211softmac_device *mac)
-{
- return mac->bssinfo.use_protection;
-}
-
-/* Start the SoftMAC. Call this after you initialized the device
- * and it is ready to run.
- */
-extern void ieee80211softmac_start(struct net_device *dev);
-/* Stop the SoftMAC. Call this before you shutdown the device. */
-extern void ieee80211softmac_stop(struct net_device *dev);
-
-/*
- * Event system
- */
-
-/* valid event types */
-#define IEEE80211SOFTMAC_EVENT_ANY -1 /*private use only*/
-#define IEEE80211SOFTMAC_EVENT_SCAN_FINISHED 0
-#define IEEE80211SOFTMAC_EVENT_ASSOCIATED 1
-#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED 2
-#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT 3
-#define IEEE80211SOFTMAC_EVENT_AUTHENTICATED 4
-#define IEEE80211SOFTMAC_EVENT_AUTH_FAILED 5
-#define IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT 6
-#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND 7
-#define IEEE80211SOFTMAC_EVENT_DISASSOCIATED 8
-/* keep this updated! */
-#define IEEE80211SOFTMAC_EVENT_LAST 8
-/*
- * If you want to be notified of certain events, you can call
- * ieee80211softmac_notify[_atomic] with
- * - event set to one of the constants below
- * - fun set to a function pointer of the appropriate type
- * - context set to the context data you want passed
- * The return value is 0, or an error.
- */
-typedef void (*notify_function_ptr)(struct net_device *dev, int event_type, void *context);
-
-#define ieee80211softmac_notify(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_KERNEL);
-#define ieee80211softmac_notify_atomic(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_ATOMIC);
-
-extern int ieee80211softmac_notify_gfp(struct net_device *dev,
- int event, notify_function_ptr fun, void *context, gfp_t gfp_mask);
-
-/* To clear pending work (for ifconfig down, etc.) */
-extern void
-ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm);
-
-#endif /* IEEE80211SOFTMAC_H_ */
+++ /dev/null
-/*
- * This file contains the prototypes for the wireless extension
- * handlers that the softmac API provides. Include this file to
- * use the wx handlers, you can assign these directly.
- *
- * Copyright (c) 2005 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#ifndef _IEEE80211SOFTMAC_WX_H
-#define _IEEE80211SOFTMAC_WX_H
-
-#include <net/ieee80211softmac.h>
-#include <net/iw_handler.h>
-
-extern int
-ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra);
-
-extern int
-ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra);
-
-extern int
-ieee80211softmac_wx_set_essid(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra);
-
-extern int
-ieee80211softmac_wx_get_essid(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra);
-
-extern int
-ieee80211softmac_wx_set_rate(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra);
-
-extern int
-ieee80211softmac_wx_get_rate(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra);
-
-extern int
-ieee80211softmac_wx_get_wap(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra);
-
-extern int
-ieee80211softmac_wx_set_wap(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra);
-
-extern int
-ieee80211softmac_wx_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra);
-
-extern int
-ieee80211softmac_wx_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra);
-extern int
-ieee80211softmac_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra);
-#endif /* _IEEE80211SOFTMAC_WX */
static inline int inet_iif(const struct sk_buff *skb)
{
- return ((struct rtable *)skb->dst)->rt_iif;
+ return skb->rtable->rt_iif;
}
#endif /* _INET_SOCK_H */
#define RT6_TABLE_LOCAL RT6_TABLE_MAIN
#endif
-typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *,
+typedef struct rt6_info *(*pol_lookup_t)(struct net *,
+ struct fib6_table *,
struct flowi *, int);
/*
* exported functions
*/
-extern struct fib6_table * fib6_get_table(u32 id);
-extern struct fib6_table * fib6_new_table(u32 id);
-extern struct dst_entry * fib6_rule_lookup(struct flowi *fl, int flags,
- pol_lookup_t lookup);
+extern struct fib6_table *fib6_get_table(struct net *net, u32 id);
+extern struct fib6_table *fib6_new_table(struct net *net, u32 id);
+extern struct dst_entry *fib6_rule_lookup(struct net *net,
+ struct flowi *fl, int flags,
+ pol_lookup_t lookup);
extern struct fib6_node *fib6_lookup(struct fib6_node *root,
struct in6_addr *daddr,
struct in6_addr *daddr, int dst_len,
struct in6_addr *saddr, int src_len);
-extern void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
+extern void fib6_clean_all(struct net *net,
+ int (*func)(struct rt6_info *, void *arg),
int prune, void *arg);
extern int fib6_add(struct fib6_node *root,
extern void inet6_rt_notify(int event, struct rt6_info *rt,
struct nl_info *info);
-extern void fib6_run_gc(unsigned long dummy);
+extern void fib6_run_gc(unsigned long expires,
+ struct net *net);
extern void fib6_gc_cleanup(void);
#define RT6_LOOKUP_F_REACHABLE 0x2
#define RT6_LOOKUP_F_HAS_SADDR 0x4
-extern struct rt6_info ip6_null_entry;
+extern struct rt6_info *ip6_null_entry;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-extern struct rt6_info ip6_prohibit_entry;
-extern struct rt6_info ip6_blk_hole_entry;
+extern struct rt6_info *ip6_prohibit_entry;
+extern struct rt6_info *ip6_blk_hole_entry;
#endif
extern void ip6_route_input(struct sk_buff *skb);
-extern struct dst_entry * ip6_route_output(struct sock *sk,
+extern struct dst_entry * ip6_route_output(struct net *net,
+ struct sock *sk,
struct flowi *fl);
extern int ip6_route_init(void);
extern void ip6_route_cleanup(void);
-extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg);
+extern int ipv6_route_ioctl(struct net *net,
+ unsigned int cmd,
+ void __user *arg);
extern int ip6_route_add(struct fib6_config *cfg);
extern int ip6_ins_rt(struct rt6_info *);
int dstlen, int srclen,
int metric, __u32 flags);
-extern struct rt6_info *rt6_lookup(struct in6_addr *daddr,
+extern struct rt6_info *rt6_lookup(struct net *net,
+ struct in6_addr *daddr,
struct in6_addr *saddr,
int oif, int flags);
-extern struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
+extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
- struct in6_addr *addr,
- int (*output)(struct sk_buff *));
-extern int ndisc_dst_gc(int *more);
-extern void fib6_force_start_gc(void);
+ struct in6_addr *addr);
+extern int icmp6_dst_gc(int *more);
+
+extern void fib6_force_start_gc(struct net *net);
extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
const struct in6_addr *addr,
struct net_device *dev,
unsigned int pref);
-extern void rt6_purge_dflt_routers(void);
+extern void rt6_purge_dflt_routers(struct net *net);
extern int rt6_route_rcv(struct net_device *dev,
u8 *opt, int len,
};
extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
-extern void rt6_ifdown(struct net_device *dev);
+extern void rt6_ifdown(struct net *net, struct net_device *dev);
extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
extern rwlock_t rt6_lock;
}
/*
+ * Check for a RFC 4843 ORCHID address
+ * (Overlay Routable Cryptographic Hash Identifiers)
+ */
+static inline int ipv6_addr_orchid(const struct in6_addr *a)
+{
+ return ((a->s6_addr32[0] & htonl(0xfffffff0))
+ == htonl(0x20010010));
+}
+
+/*
* find the first different bit between two addresses
* length of address must be a multiple of 32bits
*/
char __user *optval,
int __user *optlen);
-extern int ipv6_packet_init(void);
-
-extern void ipv6_packet_cleanup(void);
-
extern int ip6_datagram_connect(struct sock *sk,
struct sockaddr *addr, int addr_len);
extern int snmp6_register_dev(struct inet6_dev *idev);
extern int snmp6_unregister_dev(struct inet6_dev *idev);
-extern struct rt6_statistics rt6_stats;
#else
static inline int snmp6_register_dev(struct inet6_dev *idev)
{
return is_zero_ether_addr(mac);
}
-static inline int llc_addrany(const struct llc_addr *addr)
-{
- return llc_mac_null(addr->mac) && !addr->lsap;
-}
-
static inline int llc_mac_multicast(const u8 *mac)
{
return is_multicast_ether_addr(mac);
* called in hardware interrupt context. The low-level driver must not call any
* other functions in hardware interrupt context. If there is a need for such
* call, the low-level driver should first ACK the interrupt and perform the
- * IEEE 802.11 code call after this, e.g. from a scheduled workqueue function.
+ * IEEE 802.11 code call after this, e.g. from a scheduled workqueue or even
+ * tasklet function.
+ *
+ * NOTE: If the driver opts to use the _irqsafe() functions, it may not also
+ * use the non-irqsafe functions!
*/
/**
* not do so then mac80211 may add this under certain circumstances.
*/
-#define IEEE80211_CHAN_W_SCAN 0x00000001
-#define IEEE80211_CHAN_W_ACTIVE_SCAN 0x00000002
-#define IEEE80211_CHAN_W_IBSS 0x00000004
-
-/* Channel information structure. Low-level driver is expected to fill in chan,
- * freq, and val fields. Other fields will be filled in by 80211.o based on
- * hostapd information and low-level driver does not need to use them. The
- * limits for each channel will be provided in 'struct ieee80211_conf' when
- * configuring the low-level driver with hw->config callback. If a device has
- * a default regulatory domain, IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED
- * can be set to let the driver configure all fields */
-struct ieee80211_channel {
- short chan; /* channel number (IEEE 802.11) */
- short freq; /* frequency in MHz */
- int val; /* hw specific value for the channel */
- int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
- unsigned char power_level;
- unsigned char antenna_max;
-};
-
-#define IEEE80211_RATE_ERP 0x00000001
-#define IEEE80211_RATE_BASIC 0x00000002
-#define IEEE80211_RATE_PREAMBLE2 0x00000004
-#define IEEE80211_RATE_SUPPORTED 0x00000010
-#define IEEE80211_RATE_OFDM 0x00000020
-#define IEEE80211_RATE_CCK 0x00000040
-#define IEEE80211_RATE_MANDATORY 0x00000100
-
-#define IEEE80211_RATE_CCK_2 (IEEE80211_RATE_CCK | IEEE80211_RATE_PREAMBLE2)
-#define IEEE80211_RATE_MODULATION(f) \
- (f & (IEEE80211_RATE_CCK | IEEE80211_RATE_OFDM))
-
-/* Low-level driver should set PREAMBLE2, OFDM and CCK flags.
- * BASIC, SUPPORTED, ERP, and MANDATORY flags are set in 80211.o based on the
- * configuration. */
-struct ieee80211_rate {
- int rate; /* rate in 100 kbps */
- int val; /* hw specific value for the rate */
- int flags; /* IEEE80211_RATE_ flags */
- int val2; /* hw specific value for the rate when using short preamble
- * (only when IEEE80211_RATE_PREAMBLE2 flag is set, i.e., for
- * 2, 5.5, and 11 Mbps) */
- signed char min_rssi_ack;
- unsigned char min_rssi_ack_delta;
-
- /* following fields are set by 80211.o and need not be filled by the
- * low-level driver */
- int rate_inv; /* inverse of the rate (LCM(all rates) / rate) for
- * optimizing channel utilization estimates */
-};
-
-/**
- * enum ieee80211_phymode - PHY modes
- *
- * @MODE_IEEE80211A: 5GHz as defined by 802.11a/802.11h
- * @MODE_IEEE80211B: 2.4 GHz as defined by 802.11b
- * @MODE_IEEE80211G: 2.4 GHz as defined by 802.11g (with OFDM),
- * backwards compatible with 11b mode
- * @NUM_IEEE80211_MODES: internal
- */
-enum ieee80211_phymode {
- MODE_IEEE80211A,
- MODE_IEEE80211B,
- MODE_IEEE80211G,
-
- /* keep last */
- NUM_IEEE80211_MODES
-};
-
-/**
- * struct ieee80211_ht_info - describing STA's HT capabilities
- *
- * This structure describes most essential parameters needed
- * to describe 802.11n HT capabilities for an STA.
- *
- * @ht_supported: is HT supported by STA, 0: no, 1: yes
- * @cap: HT capabilities map as described in 802.11n spec
- * @ampdu_factor: Maximum A-MPDU length factor
- * @ampdu_density: Minimum A-MPDU spacing
- * @supp_mcs_set: Supported MCS set as described in 802.11n spec
- */
-struct ieee80211_ht_info {
- u8 ht_supported;
- u16 cap; /* use IEEE80211_HT_CAP_ */
- u8 ampdu_factor;
- u8 ampdu_density;
- u8 supp_mcs_set[16];
-};
-
/**
* struct ieee80211_ht_bss_info - describing BSS's HT characteristics
*
};
/**
- * struct ieee80211_hw_mode - PHY mode definition
- *
- * This structure describes the capabilities supported by the device
- * in a single PHY mode.
- *
- * @list: internal
- * @channels: pointer to array of supported channels
- * @rates: pointer to array of supported bitrates
- * @mode: the PHY mode for this definition
- * @num_channels: number of supported channels
- * @num_rates: number of supported bitrates
- * @ht_info: PHY's 802.11n HT abilities for this mode
- */
-struct ieee80211_hw_mode {
- struct list_head list;
- struct ieee80211_channel *channels;
- struct ieee80211_rate *rates;
- enum ieee80211_phymode mode;
- int num_channels;
- int num_rates;
- struct ieee80211_ht_info ht_info;
-};
-
-/**
* struct ieee80211_tx_queue_params - transmit queue configuration
*
* The information provided in this structure is required for QoS
- * transmit queue configuration.
+ * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29.
*
* @aifs: arbitration interface space [0..255, -1: use default]
* @cw_min: minimum contention window [will be a value of the form
* 2^n-1 in the range 1..1023; 0: use default]
* @cw_max: maximum contention window [like @cw_min]
- * @burst_time: maximum burst time in units of 0.1ms, 0 meaning disabled
+ * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
*/
struct ieee80211_tx_queue_params {
- int aifs;
- int cw_min;
- int cw_max;
- int burst_time;
+ s16 aifs;
+ u16 cw_min;
+ u16 cw_max;
+ u16 txop;
};
/**
* @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be
* sent after a beacon
* @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames
+ * @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU
*/
enum ieee80211_tx_queue {
IEEE80211_TX_QUEUE_DATA0,
* this struct need to have fixed values. As soon as it is removed, we can
* fix these entries. */
IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
- IEEE80211_TX_QUEUE_BEACON = 7
+ IEEE80211_TX_QUEUE_BEACON = 7,
+ NUM_TX_DATA_QUEUES_AMPDU = 16
};
struct ieee80211_tx_queue_stats {
- struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES];
+ struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU];
};
struct ieee80211_low_level_stats {
bool use_short_preamble;
};
+/**
+ * enum mac80211_tx_control_flags - flags to describe Tx configuration for
+ * the Tx frame
+ *
+ * These flags are used with the @flags member of &ieee80211_tx_control
+ *
+ * @IEEE80211_TXCTL_REQ_TX_STATUS: request TX status callback for this frame.
+ * @IEEE80211_TXCTL_DO_NOT_ENCRYPT: send this frame without encryption;
+ * e.g., for EAPOL frame
+ * @IEEE80211_TXCTL_USE_RTS_CTS: use RTS-CTS before sending frame
+ * @IEEE80211_TXCTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
+ * for combined 802.11g / 802.11b networks)
+ * @IEEE80211_TXCTL_NO_ACK: tell the low level not to wait for an ack
+ * @IEEE80211_TXCTL_RATE_CTRL_PROBE
+ * @EEE80211_TXCTL_CLEAR_PS_FILT: clear powersave filter
+ * for destination station
+ * @IEEE80211_TXCTL_REQUEUE:
+ * @IEEE80211_TXCTL_FIRST_FRAGMENT: this is a first fragment of the frame
+ * @IEEE80211_TXCTL_LONG_RETRY_LIMIT: this frame should be send using the
+ * through set_retry_limit configured long
+ * retry value
+ * @IEEE80211_TXCTL_EAPOL_FRAME: internal to mac80211
+ * @IEEE80211_TXCTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
+ * @IEEE80211_TXCTL_AMPDU: this frame should be sent as part of an A-MPDU
+ * @IEEE80211_TXCTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
+ * of streams when this flag is on can be extracted
+ * from antenna_sel_tx, so if 1 antenna is marked
+ * use SISO, 2 antennas marked use MIMO, n antennas
+ * marked use MIMO_n.
+ * @IEEE80211_TXCTL_GREEN_FIELD: use green field protection for this frame
+ * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
+ * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
+ * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval
+ */
+enum mac80211_tx_control_flags {
+ IEEE80211_TXCTL_REQ_TX_STATUS = (1<<0),
+ IEEE80211_TXCTL_DO_NOT_ENCRYPT = (1<<1),
+ IEEE80211_TXCTL_USE_RTS_CTS = (1<<2),
+ IEEE80211_TXCTL_USE_CTS_PROTECT = (1<<3),
+ IEEE80211_TXCTL_NO_ACK = (1<<4),
+ IEEE80211_TXCTL_RATE_CTRL_PROBE = (1<<5),
+ IEEE80211_TXCTL_CLEAR_PS_FILT = (1<<6),
+ IEEE80211_TXCTL_REQUEUE = (1<<7),
+ IEEE80211_TXCTL_FIRST_FRAGMENT = (1<<8),
+ IEEE80211_TXCTL_SHORT_PREAMBLE = (1<<9),
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT = (1<<10),
+ IEEE80211_TXCTL_EAPOL_FRAME = (1<<11),
+ IEEE80211_TXCTL_SEND_AFTER_DTIM = (1<<12),
+ IEEE80211_TXCTL_AMPDU = (1<<13),
+ IEEE80211_TXCTL_OFDM_HT = (1<<14),
+ IEEE80211_TXCTL_GREEN_FIELD = (1<<15),
+ IEEE80211_TXCTL_40_MHZ_WIDTH = (1<<16),
+ IEEE80211_TXCTL_DUP_DATA = (1<<17),
+ IEEE80211_TXCTL_SHORT_GI = (1<<18),
+};
+
/* Transmit control fields. This data structure is passed to low-level driver
* with each TX frame. The low-level driver is responsible for configuring
* the hardware to use given values (depending on what is supported). */
struct ieee80211_tx_control {
struct ieee80211_vif *vif;
- int tx_rate; /* Transmit rate, given as the hw specific value for the
- * rate (from struct ieee80211_rate) */
- int rts_cts_rate; /* Transmit rate for RTS/CTS frame, given as the hw
- * specific value for the rate (from
- * struct ieee80211_rate) */
-
-#define IEEE80211_TXCTL_REQ_TX_STATUS (1<<0)/* request TX status callback for
- * this frame */
-#define IEEE80211_TXCTL_DO_NOT_ENCRYPT (1<<1) /* send this frame without
- * encryption; e.g., for EAPOL
- * frames */
-#define IEEE80211_TXCTL_USE_RTS_CTS (1<<2) /* use RTS-CTS before sending
- * frame */
-#define IEEE80211_TXCTL_USE_CTS_PROTECT (1<<3) /* use CTS protection for the
- * frame (e.g., for combined
- * 802.11g / 802.11b networks) */
-#define IEEE80211_TXCTL_NO_ACK (1<<4) /* tell the low level not to
- * wait for an ack */
-#define IEEE80211_TXCTL_RATE_CTRL_PROBE (1<<5)
-#define IEEE80211_TXCTL_CLEAR_DST_MASK (1<<6)
-#define IEEE80211_TXCTL_REQUEUE (1<<7)
-#define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of
- * the frame */
-#define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send
- * using the through
- * set_retry_limit configured
- * long retry value */
-#define IEEE80211_TXCTL_EAPOL_FRAME (1<<11) /* internal to mac80211 */
-#define IEEE80211_TXCTL_SEND_AFTER_DTIM (1<<12) /* send this frame after DTIM
- * beacon */
- u32 flags; /* tx control flags defined
- * above */
+ struct ieee80211_rate *tx_rate;
+
+ /* Transmit rate for RTS/CTS frame */
+ struct ieee80211_rate *rts_cts_rate;
+
+ /* retry rate for the last retries */
+ struct ieee80211_rate *alt_retry_rate;
+
+ u32 flags; /* tx control flags defined above */
u8 key_idx; /* keyidx from hw->set_key(), undefined if
* IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */
u8 retry_limit; /* 1 = only first attempt, 2 = one retry, ..
* This could be used when set_retry_limit
* is not implemented by the driver */
- u8 power_level; /* per-packet transmit power level, in dBm */
- u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
+ u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit
+ * position represents antenna number used */
u8 icv_len; /* length of the ICV/MIC field in octets */
u8 iv_len; /* length of the IV field in octets */
u8 queue; /* hardware queue to use for this frame;
* 0 = highest, hw->queues-1 = lowest */
- struct ieee80211_rate *rate; /* internal 80211.o rate */
- struct ieee80211_rate *rts_rate; /* internal 80211.o rate
- * for RTS/CTS */
- int alt_retry_rate; /* retry rate for the last retries, given as the
- * hw specific value for the rate (from
- * struct ieee80211_rate). To be used to limit
- * packet dropping when probing higher rates, if hw
- * supports multiple retry rates. -1 = not used */
int type; /* internal */
};
* @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
* the frame.
* @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field)
- * is valid.
+ * is valid. This is useful in monitor mode and necessary for beacon frames
+ * to enable IBSS merging.
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = 1<<0,
* The low-level driver should provide this information (the subset
* supported by hardware) to the 802.11 code with each received
* frame.
- * @mactime: MAC timestamp as defined by 802.11
+ * @mactime: value in microseconds of the 64-bit Time Synchronization Function
+ * (TSF) timer when the first data symbol (MPDU) arrived at the hardware.
+ * @band: the active band when this frame was received
* @freq: frequency the radio was tuned to when receiving this frame, in MHz
- * @channel: channel the radio was tuned to
- * @phymode: active PHY mode
* @ssi: signal strength when receiving this frame
* @signal: used as 'qual' in statistics reporting
* @noise: PHY noise when receiving this frame
* @antenna: antenna used
- * @rate: data rate
+ * @rate_idx: index of data rate into band's supported rates
* @flag: %RX_FLAG_*
*/
struct ieee80211_rx_status {
u64 mactime;
+ enum ieee80211_band band;
int freq;
- int channel;
- enum ieee80211_phymode phymode;
int ssi;
int signal;
int noise;
int antenna;
- int rate;
+ int rate_idx;
int flag;
};
*
* @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted
* because the destination STA was in powersave mode.
- *
* @IEEE80211_TX_STATUS_ACK: Frame was acknowledged
+ * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status
+ * is for the whole aggregation.
*/
enum ieee80211_tx_status_flags {
IEEE80211_TX_STATUS_TX_FILTERED = 1<<0,
IEEE80211_TX_STATUS_ACK = 1<<1,
+ IEEE80211_TX_STATUS_AMPDU = 1<<2,
};
/**
*
* @control: a copy of the &struct ieee80211_tx_control passed to the driver
* in the tx() callback.
- *
* @flags: transmit status flags, defined above
- *
- * @ack_signal: signal strength of the ACK frame
- *
+ * @retry_count: number of retries
* @excessive_retries: set to 1 if the frame was retried many times
* but not acknowledged
- *
- * @retry_count: number of retries
- *
+ * @ampdu_ack_len: number of aggregated frames.
+ * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ampdu_ack_map: block ack bit map for the aggregation.
+ * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ack_signal: signal strength of the ACK frame
* @queue_length: ?? REMOVE
* @queue_number: ?? REMOVE
*/
struct ieee80211_tx_status {
struct ieee80211_tx_control control;
u8 flags;
- bool excessive_retries;
u8 retry_count;
+ bool excessive_retries;
+ u8 ampdu_ack_len;
+ u64 ampdu_ack_map;
int ack_signal;
int queue_length;
int queue_number;
*
* @radio_enabled: when zero, driver is required to switch off the radio.
* TODO make a flag
- * @channel: IEEE 802.11 channel number
- * @freq: frequency in MHz
- * @channel_val: hardware specific channel value for the channel
- * @phymode: PHY mode to activate (REMOVE)
- * @chan: channel to switch to, pointer to the channel information
- * @mode: pointer to mode definition
- * @regulatory_domain: ??
* @beacon_int: beacon interval (TODO make interface config)
* @flags: configuration flags defined above
- * @power_level: transmit power limit for current regulatory domain in dBm
- * @antenna_max: maximum antenna gain
+ * @power_level: requested transmit power (in dBm)
+ * @max_antenna_gain: maximum antenna gain (in dBi)
* @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
* 1/2: antenna 0/1
* @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
* @ht_conf: describes current self configuration of 802.11n HT capabilies
* @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
+ * @channel: the channel to tune to
*/
struct ieee80211_conf {
- int channel; /* IEEE 802.11 channel number */
- int freq; /* MHz */
- int channel_val; /* hw specific value for the channel */
-
- enum ieee80211_phymode phymode;
- struct ieee80211_channel *chan;
- struct ieee80211_hw_mode *mode;
- unsigned int regulatory_domain;
int radio_enabled;
int beacon_int;
u32 flags;
- u8 power_level;
- u8 antenna_max;
+ int power_level;
+ int max_antenna_gain;
u8 antenna_sel_tx;
u8 antenna_sel_rx;
+ struct ieee80211_channel *channel;
+
struct ieee80211_ht_info ht_conf;
struct ieee80211_ht_bss_info ht_bss_conf;
};
* @IEEE80211_IF_TYPE_WDS: interface in WDS mode.
* @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers
* will never see this type.
+ * @IEEE80211_IF_TYPE_MESH_POINT: 802.11s mesh point
*/
enum ieee80211_if_types {
IEEE80211_IF_TYPE_INVALID,
IEEE80211_IF_TYPE_AP,
IEEE80211_IF_TYPE_STA,
IEEE80211_IF_TYPE_IBSS,
+ IEEE80211_IF_TYPE_MESH_POINT,
IEEE80211_IF_TYPE_MNTR,
IEEE80211_IF_TYPE_WDS,
IEEE80211_IF_TYPE_VLAN,
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
};
+static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return vif->type == IEEE80211_IF_TYPE_MESH_POINT;
+#endif
+ return false;
+}
+
/**
* struct ieee80211_if_init_conf - initial configuration of an interface
*
* %IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is also not set because
* otherwise the stack will not know when the DTIM beacon was sent.
*
- * @IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED:
- * Channels are already configured to the default regulatory domain
- * specified in the device's EEPROM
+ * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE:
+ * Hardware is not capable of short slot operation on the 2.4 GHz band.
+ *
+ * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE:
+ * Hardware is not capable of receiving frames with short preamble on
+ * the 2.4 GHz band.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0,
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2,
- IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED = 1<<3,
+ IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3,
+ IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4,
};
/**
* @wiphy: This points to the &struct wiphy allocated for this
* 802.11 PHY. You must fill in the @perm_addr and @dev
* members of this structure using SET_IEEE80211_DEV()
- * and SET_IEEE80211_PERM_ADDR().
+ * and SET_IEEE80211_PERM_ADDR(). Additionally, all supported
+ * bands (with channels, bitrates) are registered here.
*
* @conf: &struct ieee80211_conf, device configuration, don't use.
*
* parameter to see whether multicast frames should be accepted
* or dropped.
*
- * All unsupported flags in @total_flags must be cleared, i.e. you
- * should clear all bits except those you honoured.
+ * All unsupported flags in @total_flags must be cleared.
+ * Hardware does not support a flag if it is incapable of _passing_
+ * the frame to the stack. Otherwise the driver must ignore
+ * the flag, but not clear it.
+ * You must _only_ clear the flag (announce no support for the
+ * flag to mac80211) if you are not able to pass the packet type
+ * to the stack (so the hardware always filters it).
+ * So for example, you should clear @FIF_CONTROL, if your hardware
+ * always filters control frames. If your hardware always passes
+ * control frames to the kernel and is incapable of filtering them,
+ * you do _not_ clear the @FIF_CONTROL flag.
+ * This rule applies to all other FIF flags as well.
*/
/**
* &struct ieee80211_ops to indicate which action is needed.
* @IEEE80211_AMPDU_RX_START: start Rx aggregation
* @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation
+ * @IEEE80211_AMPDU_TX_START: start Tx aggregation
+ * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation
*/
enum ieee80211_ampdu_mlme_action {
IEEE80211_AMPDU_RX_START,
IEEE80211_AMPDU_RX_STOP,
+ IEEE80211_AMPDU_TX_START,
+ IEEE80211_AMPDU_TX_STOP,
};
/**
* given local_address is enabled.
*
* @hw_scan: Ask the hardware to service the scan request, no need to start
- * the scan state machine in stack.
+ * the scan state machine in stack. The scan must honour the channel
+ * configuration done by the regulatory agent in the wiphy's registered
+ * bands.
*
* @get_stats: return low-level statistics
*
* The RA/TID combination determines the destination and TID we want
* the ampdu action to be performed for. The action is defined through
* ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
- * is the first frame we expect to perform the action on.
+ * is the first frame we expect to perform the action on. notice
+ * that TX/RX_STOP can pass NULL for this parameter.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
int (*conf_ht)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
int (*ampdu_action)(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
- const u8 *ra, u16 tid, u16 ssn);
+ const u8 *addr, u16 tid, u16 *ssn);
};
/**
/**
* ieee80211_register_hw - Register hardware device
*
- * You must call this function before any other functions
- * except ieee80211_register_hwmode.
+ * You must call this function before any other functions in
+ * mac80211. Note that before a hardware can be registered, you
+ * need to fill the contained wiphy's information.
*
* @hw: the device to register as returned by ieee80211_alloc_hw()
*/
#endif
}
-/* Register a new hardware PHYMODE capability to the stack. */
-int ieee80211_register_hwmode(struct ieee80211_hw *hw,
- struct ieee80211_hw_mode *mode);
-
/**
* ieee80211_unregister_hw - Unregister a hardware device
*
* buffer in @skb must start with an IEEE 802.11 header or a radiotap
* header if %RX_FLAG_RADIOTAP is set in the @status flags.
*
- * This function may not be called in IRQ context.
+ * This function may not be called in IRQ context. Calls to this function
+ * for a single hardware must be synchronized against each other. Calls
+ * to this function and ieee80211_rx_irqsafe() may not be mixed for a
+ * single hardware.
*
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call
* ieee80211_rx_irqsafe - receive frame
*
* Like ieee80211_rx() but can be called in IRQ context
- * (internally defers to a workqueue.)
+ * (internally defers to a tasklet.)
+ *
+ * Calls to this function and ieee80211_rx() may not be mixed for a
+ * single hardware.
*
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call
* transmitted. It is permissible to not call this function for
* multicast frames but this can affect statistics.
*
+ * This function may not be called in IRQ context. Calls to this function
+ * for a single hardware must be synchronized against each other. Calls
+ * to this function and ieee80211_tx_status_irqsafe() may not be mixed
+ * for a single hardware.
+ *
* @hw: the hardware the frame was transmitted by
* @skb: the frame that was transmitted, owned by mac80211 after this call
* @status: status information for this frame; the status pointer need not
void ieee80211_tx_status(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_tx_status *status);
+
+/**
+ * ieee80211_tx_status_irqsafe - irq-safe transmit status callback
+ *
+ * Like ieee80211_tx_status() but can be called in IRQ context
+ * (internally defers to a tasklet.)
+ *
+ * Calls to this function and ieee80211_tx_status() may not be mixed for a
+ * single hardware.
+ *
+ * @hw: the hardware the frame was transmitted by
+ * @skb: the frame that was transmitted, owned by mac80211 after this call
+ * @status: status information for this frame; the status pointer need not
+ * be valid after this function returns and is not freed by mac80211,
+ * it is recommended that it points to a stack area
+ */
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_tx_status *status);
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @frame_len: the length of the frame.
- * @rate: the rate (in 100kbps) at which the frame is going to be transmitted.
+ * @rate: the rate at which the frame is going to be transmitted.
*
* Calculate the duration field of some generic frame, given its
* length and transmission rate (in 100kbps).
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
size_t frame_len,
- int rate);
+ struct ieee80211_rate *rate);
/**
* ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
struct ieee80211_vif *vif),
void *data);
+/**
+ * ieee80211_start_tx_ba_session - Start a tx Block Ack session.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient
+ * @tid: the TID to BA on.
+ * @return: success if addBA request was sent, failure otherwise
+ *
+ * Although mac80211/low level driver/user space application can estimate
+ * the need to start aggregation on a certain RA/TID, the session level
+ * will be managed by the mac80211.
+ */
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid);
+
+/**
+ * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session.
+ */
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
+
+/**
+ * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session.
+ * This version of the function is irq safe.
+ */
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
+ u16 tid);
+
+/**
+ * ieee80211_stop_tx_ba_session - Stop a Block Ack session.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient
+ * @tid: the TID to stop BA.
+ * @initiator: if indicates initiator DELBA frame will be sent.
+ * @return: error if no sta with matching da found, success otherwise
+ *
+ * Although mac80211/low level driver/user space application can estimate
+ * the need to stop aggregation on a certain RA/TID, the session level
+ * will be managed by the mac80211.
+ */
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+ u8 *ra, u16 tid,
+ enum ieee80211_back_parties initiator);
+
+/**
+ * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the desired TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session tear down.
+ */
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
+
+/**
+ * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the desired TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session tear down.
+ * This version of the function is irq safe.
+ */
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
+ u16 tid);
+
#endif /* MAC80211_H */
} __attribute__((__packed__));
-extern int ndisc_init(struct net_proto_family *ops);
+extern int ndisc_init(void);
extern void ndisc_cleanup(void);
/*
* IGMP
*/
-extern int igmp6_init(struct net_proto_family *ops);
+extern int igmp6_init(void);
extern void igmp6_cleanup(void);
neigh->confirmed = jiffies;
}
-static inline int neigh_is_connected(struct neighbour *neigh)
-{
- return neigh->nud_state&NUD_CONNECTED;
-}
-
-
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
neigh->used = jiffies;
struct hlist_head *fib_table_hash;
struct sock *fibnl;
+ struct sock **icmp_sk;
+
struct netns_frags frags;
#ifdef CONFIG_NETFILTER
struct xt_table *iptable_filter;
struct xt_table *ip6table_mangle;
struct xt_table *ip6table_raw;
#endif
+ struct rt6_info *ip6_null_entry;
+ struct rt6_statistics *rt6_stats;
+ struct timer_list *ip6_fib_timer;
+ struct hlist_head *fib_table_hash;
+ struct fib6_table *fib6_main_tbl;
+ struct dst_ops *ip6_dst_ops;
+ unsigned int ip6_rt_gc_expire;
+ unsigned long ip6_rt_last_gc;
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ struct rt6_info *ip6_prohibit_entry;
+ struct rt6_info *ip6_blk_hole_entry;
+ struct fib6_table *fib6_local_tbl;
+ struct fib_rules_ops *fib6_rules_ops;
+#endif
+ struct sock **icmp_sk;
+ struct sock *ndisc_sk;
+ struct sock *tcp_sk;
+ struct sock *igmp_sk;
};
#endif
int obj_size;
struct kmem_cache *slab;
int (*rtx_syn_ack)(struct sock *sk,
- struct request_sock *req,
- struct dst_entry *dst);
+ struct request_sock *req);
void (*send_ack)(struct sk_buff *skb,
struct request_sock *req);
void (*send_reset)(struct sock *sk,
#else
static inline void sctp_sysctl_register(void) { return; }
static inline void sctp_sysctl_unregister(void) { return; }
-static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen) {
- return -ENOSYS;
-}
#endif
/* Size of Supported Address Parameter for 'x' address types. */
/* Transport to which SHUTDOWN chunk was last sent. */
struct sctp_transport *shutdown_last_sent_to;
+ /* How many times have we resent a SHUTDOWN */
+ int shutdown_retries;
+
/* Transport to which INIT chunk was last sent. */
struct sctp_transport *init_last_sent_to;
*/
__u16 unack_data;
+ /* The total number of data chunks that we've had to retransmit
+ * as the result of a T3 timer expiration
+ */
+ __u32 rtx_data_chunks;
+
/* This is the association's receive buffer space. This value is used
* to set a_rwnd field in an INIT or a SACK chunk.
*/
gfp_t priority,
struct proto *prot);
extern void sk_free(struct sock *sk);
+extern void sk_release_kernel(struct sock *sk);
extern struct sock *sk_clone(const struct sock *sk,
const gfp_t priority);
}
#endif
+/*
+ * Kernel sockets, f.e. rtnl or icmp_socket, are a part of a namespace.
+ * They should not hold a referrence to a namespace in order to allow
+ * to stop it.
+ * Sockets after sk_change_net should be released using sk_release_kernel
+ */
+static inline void sk_change_net(struct sock *sk, struct net *net)
+{
+ put_net(sk->sk_net);
+ sk->sk_net = net;
+}
+
extern void sock_enable_timestamp(struct sock *sk);
extern int sock_get_timestamp(struct sock *, struct timeval __user *);
extern int sock_get_timestampns(struct sock *, struct timespec __user *);
#include <linux/skbuff.h>
#include <linux/dmaengine.h>
#include <linux/crypto.h>
+#include <linux/cryptohash.h>
#include <net/inet_connection_sock.h>
#include <net/inet_timewait_sock.h>
extern void tcp_unhash(struct sock *sk);
/* From syncookies.c */
+extern __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt);
extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
__u16 *mss);
+/* From net/ipv6/syncookies.c */
+extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
+extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb,
+ __u16 *mss);
+
/* tcp_output.c */
extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
extern struct request_sock_ops tcp_request_sock_ops;
+extern struct request_sock_ops tcp6_request_sock_ops;
extern int tcp_v4_destroy_sock(struct sock *sk);
#endif
};
-extern void tcp_v4_init(struct net_proto_family *ops);
+extern void tcp_v4_init(void);
extern void tcp_init(void);
#endif /* _TCP_H */
char name[TIPC_MAX_BEARER_NAME];
};
+/*
+ * TIPC routines available to supported media types
+ */
int tipc_register_media(u32 media_type,
char *media_name,
int tipc_enable_bearer(const char *bearer_name, u32 bcast_scope, u32 priority);
int tipc_disable_bearer(const char *name);
+/*
+ * Routines made available to TIPC by supported media types
+ */
+
+int tipc_eth_media_start(void);
+void tipc_eth_media_stop(void);
#endif
void (*wakeup)(struct tipc_port *),
const u32 importance);
-/*
- * tipc_set_msg_option(): port must be locked.
- */
-int tipc_set_msg_option(struct tipc_port *tp_ptr,
- const char *opt,
- const u32 len);
-
int tipc_reject_msg(struct sk_buff *buf, u32 err);
int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode);
#include <net/cfg80211.h>
/**
+ * enum ieee80211_band - supported frequency bands
+ *
+ * The bands are assigned this way because the supported
+ * bitrates differ in these bands.
+ *
+ * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band
+ * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
+ */
+enum ieee80211_band {
+ IEEE80211_BAND_2GHZ,
+ IEEE80211_BAND_5GHZ,
+
+ /* keep last */
+ IEEE80211_NUM_BANDS
+};
+
+/**
+ * enum ieee80211_channel_flags - channel flags
+ *
+ * Channel flags set by the regulatory control code.
+ *
+ * @IEEE80211_CHAN_DISABLED: This channel is disabled.
+ * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
+ * on this channel.
+ * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
+ * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
+ */
+enum ieee80211_channel_flags {
+ IEEE80211_CHAN_DISABLED = 1<<0,
+ IEEE80211_CHAN_PASSIVE_SCAN = 1<<1,
+ IEEE80211_CHAN_NO_IBSS = 1<<2,
+ IEEE80211_CHAN_RADAR = 1<<3,
+};
+
+/**
+ * struct ieee80211_channel - channel definition
+ *
+ * This structure describes a single channel for use
+ * with cfg80211.
+ *
+ * @center_freq: center frequency in MHz
+ * @hw_value: hardware-specific value for the channel
+ * @flags: channel flags from &enum ieee80211_channel_flags.
+ * @orig_flags: channel flags at registration time, used by regulatory
+ * code to support devices with additional restrictions
+ * @band: band this channel belongs to.
+ * @max_antenna_gain: maximum antenna gain in dBi
+ * @max_power: maximum transmission power (in dBm)
+ * @orig_mag: internal use
+ * @orig_mpwr: internal use
+ */
+struct ieee80211_channel {
+ enum ieee80211_band band;
+ u16 center_freq;
+ u16 hw_value;
+ u32 flags;
+ int max_antenna_gain;
+ int max_power;
+ u32 orig_flags;
+ int orig_mag, orig_mpwr;
+};
+
+/**
+ * enum ieee80211_rate_flags - rate flags
+ *
+ * Hardware/specification flags for rates. These are structured
+ * in a way that allows using the same bitrate structure for
+ * different bands/PHY modes.
+ *
+ * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short
+ * preamble on this bitrate; only relevant in 2.4GHz band and
+ * with CCK rates.
+ * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate
+ * when used with 802.11a (on the 5 GHz band); filled by the
+ * core code when registering the wiphy.
+ * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate
+ * when used with 802.11b (on the 2.4 GHz band); filled by the
+ * core code when registering the wiphy.
+ * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate
+ * when used with 802.11g (on the 2.4 GHz band); filled by the
+ * core code when registering the wiphy.
+ * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode.
+ */
+enum ieee80211_rate_flags {
+ IEEE80211_RATE_SHORT_PREAMBLE = 1<<0,
+ IEEE80211_RATE_MANDATORY_A = 1<<1,
+ IEEE80211_RATE_MANDATORY_B = 1<<2,
+ IEEE80211_RATE_MANDATORY_G = 1<<3,
+ IEEE80211_RATE_ERP_G = 1<<4,
+};
+
+/**
+ * struct ieee80211_rate - bitrate definition
+ *
+ * This structure describes a bitrate that an 802.11 PHY can
+ * operate with. The two values @hw_value and @hw_value_short
+ * are only for driver use when pointers to this structure are
+ * passed around.
+ *
+ * @flags: rate-specific flags
+ * @bitrate: bitrate in units of 100 Kbps
+ * @hw_value: driver/hardware value for this rate
+ * @hw_value_short: driver/hardware value for this rate when
+ * short preamble is used
+ */
+struct ieee80211_rate {
+ u32 flags;
+ u16 bitrate;
+ u16 hw_value, hw_value_short;
+};
+
+/**
+ * struct ieee80211_ht_info - describing STA's HT capabilities
+ *
+ * This structure describes most essential parameters needed
+ * to describe 802.11n HT capabilities for an STA.
+ *
+ * @ht_supported: is HT supported by STA, 0: no, 1: yes
+ * @cap: HT capabilities map as described in 802.11n spec
+ * @ampdu_factor: Maximum A-MPDU length factor
+ * @ampdu_density: Minimum A-MPDU spacing
+ * @supp_mcs_set: Supported MCS set as described in 802.11n spec
+ */
+struct ieee80211_ht_info {
+ u16 cap; /* use IEEE80211_HT_CAP_ */
+ u8 ht_supported;
+ u8 ampdu_factor;
+ u8 ampdu_density;
+ u8 supp_mcs_set[16];
+};
+
+/**
+ * struct ieee80211_supported_band - frequency band definition
+ *
+ * This structure describes a frequency band a wiphy
+ * is able to operate in.
+ *
+ * @channels: Array of channels the hardware can operate in
+ * in this band.
+ * @band: the band this structure represents
+ * @n_channels: Number of channels in @channels
+ * @bitrates: Array of bitrates the hardware can operate with
+ * in this band. Must be sorted to give a valid "supported
+ * rates" IE, i.e. CCK rates first, then OFDM.
+ * @n_bitrates: Number of bitrates in @bitrates
+ */
+struct ieee80211_supported_band {
+ struct ieee80211_channel *channels;
+ struct ieee80211_rate *bitrates;
+ enum ieee80211_band band;
+ int n_channels;
+ int n_bitrates;
+ struct ieee80211_ht_info ht_info;
+};
+
+/**
* struct wiphy - wireless hardware description
* @idx: the wiphy index assigned to this item
* @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
* help determine whether you own this wiphy or not. */
void *privid;
+ struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
+
/* fields below are read-only, assigned by cfg80211 */
/* the item in /sys/class/ieee80211/ points to this,
*/
extern void wiphy_free(struct wiphy *wiphy);
+/**
+ * ieee80211_channel_to_frequency - convert channel number to frequency
+ */
+extern int ieee80211_channel_to_frequency(int chan);
+
+/**
+ * ieee80211_frequency_to_channel - convert frequency to channel number
+ */
+extern int ieee80211_frequency_to_channel(int freq);
+
#endif /* __NET_WIRELESS_H */
struct xfrm_state
{
/* Note: bydst is re-used during gc */
+ struct list_head all;
struct hlist_node bydst;
struct hlist_node bysrc;
struct hlist_node byspi;
struct xfrm_policy
{
struct xfrm_policy *next;
+ struct list_head bytype;
struct hlist_node bydst;
struct hlist_node byidx;
int priority;
};
+struct xfrm_state_walk {
+ struct xfrm_state *state;
+ int count;
+ u8 proto;
+};
+
+struct xfrm_policy_walk {
+ struct xfrm_policy *policy;
+ int count;
+ u8 type, cur_type;
+};
+
extern void xfrm_init(void);
extern void xfrm4_init(void);
extern void xfrm_state_init(void);
extern int xfrm_proc_init(void);
#endif
-extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *);
+static inline void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
+{
+ walk->proto = proto;
+ walk->state = NULL;
+ walk->count = 0;
+}
+
+static inline void xfrm_state_walk_done(struct xfrm_state_walk *walk)
+{
+ if (walk->state != NULL) {
+ xfrm_state_put(walk->state);
+ walk->state = NULL;
+ }
+}
+
+extern int xfrm_state_walk(struct xfrm_state_walk *walk,
+ int (*func)(struct xfrm_state *, int, void*), void *);
extern struct xfrm_state *xfrm_state_alloc(void);
extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
struct flowi *fl, struct xfrm_tmpl *tmpl,
#endif
struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
-extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
+
+static inline void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
+{
+ walk->cur_type = XFRM_POLICY_TYPE_MAIN;
+ walk->type = type;
+ walk->policy = NULL;
+ walk->count = 0;
+}
+
+static inline void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
+{
+ if (walk->policy != NULL) {
+ xfrm_pol_put(walk->policy);
+ walk->policy = NULL;
+ }
+}
+
+extern int xfrm_policy_walk(struct xfrm_policy_walk *walk,
+ int (*func)(struct xfrm_policy *, int, int, void*), void *);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
struct xfrm_selector *sel,
skb->dev = __find_vlan_dev(dev, vid);
if (!skb->dev) {
pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
- __FUNCTION__, (unsigned int)vid, dev->name);
+ __func__, (unsigned int)vid, dev->name);
goto err_unlock;
}
ntohs(vhdr->h_vlan_TCI));
pr_debug("%s: priority: %u for TCI: %hu\n",
- __FUNCTION__, skb->priority, ntohs(vhdr->h_vlan_TCI));
+ __func__, skb->priority, ntohs(vhdr->h_vlan_TCI));
switch (skb->pkt_type) {
case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
struct net_device *vdev = dev;
pr_debug("%s: skb: %p type: %hx len: %u vlan_id: %hx, daddr: %p\n",
- __FUNCTION__, skb, type, len, vlan_dev_info(dev)->vlan_id,
+ __func__, skb, type, len, vlan_dev_info(dev)->vlan_id,
daddr);
/* build vlan header only if re_order_header flag is NOT set. This
return -ENOMEM;
}
vlan_dev_info(vdev)->cnt_inc_headroom_on_tx++;
- pr_debug("%s: %s: had to grow skb\n", __FUNCTION__, vdev->name);
+ pr_debug("%s: %s: had to grow skb\n", __func__, vdev->name);
}
if (build_vlan_header) {
vlan_dev_info(dev)->cnt_encap_on_xmit++;
pr_debug("%s: proto to encap: 0x%hx\n",
- __FUNCTION__, ntohs(veth->h_vlan_proto));
+ __func__, ntohs(veth->h_vlan_proto));
/* Construct the second two bytes. This field looks something
* like:
* usr_priority: 3 bits (high bits)
}
pr_debug("%s: about to send skb: %p to dev: %s\n",
- __FUNCTION__, skb, skb->dev->name);
+ __func__, skb, skb->dev->name);
pr_debug(" " MAC_FMT " " MAC_FMT " %4hx %4hx %4hx\n",
veth->h_dest[0], veth->h_dest[1], veth->h_dest[2],
veth->h_dest[3], veth->h_dest[4], veth->h_dest[5],
return 0;
err:
- pr_err("%s: can't create entry in proc filesystem!\n", __FUNCTION__);
+ pr_err("%s: can't create entry in proc filesystem!\n", __func__);
vlan_proc_cleanup();
return -ENOBUFS;
}
if (errno == 0) {
/* TODO: if error isn't found, add it dynamically */
errstr[len] = 0;
- printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
+ printk(KERN_ERR "%s: errstr :%s: not found\n", __func__,
errstr);
errno = 1;
}
---help---
These are the protocols used on the Internet and on most local
Ethernets. It is highly recommended to say Y here (this will enlarge
- your kernel by about 144 KB), since some programs (e.g. the X window
+ your kernel by about 400 KB), since some programs (e.g. the X window
system) use TCP/IP even if your machine is not connected to any
other computer. You will get the so-called loopback device which
allows you to ping yourself (great fun, that!).
static int aarp_seq_open(struct inode *inode, struct file *file)
{
- struct seq_file *seq;
- int rc = -ENOMEM;
- struct aarp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
- if (!s)
- goto out;
-
- rc = seq_open(file, &aarp_seq_ops);
- if (rc)
- goto out_kfree;
-
- seq = file->private_data;
- seq->private = s;
- memset(s, 0, sizeof(*s));
-out:
- return rc;
-out_kfree:
- kfree(s);
- goto out;
+ return seq_open_private(file, &aarp_seq_ops,
+ sizeof(struct aarp_iter_state));
}
const struct file_operations atalk_seq_arp_fops = {
struct in_device *in_dev;
in_dev = ((struct in_ifaddr *)ifa)->ifa_dev;
- if (!in_dev || !in_dev->dev) {
- printk(KERN_WARNING "clip_inet_event: no device\n");
- return NOTIFY_DONE;
- }
/*
* Transitions are of the down-change-up type, so it's sufficient to
* handle the change on up.
static int lec_seq_open(struct inode *inode, struct file *file)
{
- struct lec_state *state;
- struct seq_file *seq;
- int rc = -EAGAIN;
-
- state = kmalloc(sizeof(*state), GFP_KERNEL);
- if (!state) {
- rc = -ENOMEM;
- goto out;
- }
-
- rc = seq_open(file, &lec_seq_ops);
- if (rc)
- goto out_kfree;
- seq = file->private_data;
- seq->private = state;
-out:
- return rc;
-
-out_kfree:
- kfree(state);
- goto out;
-}
-
-static int lec_seq_release(struct inode *inode, struct file *file)
-{
- return seq_release_private(inode, file);
+ return seq_open_private(file, &lec_seq_ops, sizeof(struct lec_state));
}
static const struct file_operations lec_seq_fops = {
.open = lec_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = lec_seq_release,
+ .release = seq_release_private,
};
#endif
int family, const struct seq_operations *ops)
{
struct vcc_state *state;
- struct seq_file *seq;
- int rc = -ENOMEM;
- state = kmalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
- goto out;
-
- rc = seq_open(file, ops);
- if (rc)
- goto out_kfree;
+ state = __seq_open_private(file, ops, sizeof(*state));
+ if (state == NULL)
+ return -ENOMEM;
state->family = family;
-
- seq = file->private_data;
- seq->private = state;
-out:
- return rc;
-out_kfree:
- kfree(state);
- goto out;
-}
-
-static int vcc_seq_release(struct inode *inode, struct file *file)
-{
- return seq_release_private(inode, file);
+ return 0;
}
static void *vcc_seq_start(struct seq_file *seq, loff_t *pos)
.open = pvc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = vcc_seq_release,
+ .release = seq_release_private,
};
static int vcc_seq_show(struct seq_file *seq, void *v)
.open = vcc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = vcc_seq_release,
+ .release = seq_release_private,
};
static int svc_seq_show(struct seq_file *seq, void *v)
.open = svc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = vcc_seq_release,
+ .release = seq_release_private,
};
static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
}
nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
- skb->dst = (struct dst_entry *)&__fake_rtable;
- dst_hold(skb->dst);
+ skb->rtable = &__fake_rtable;
+ dst_hold(&__fake_rtable.u.dst);
skb->dev = nf_bridge->physindev;
nf_bridge_push_encap_header(skb);
skb->pkt_type = PACKET_HOST;
}
} else {
- skb->dst = (struct dst_entry *)&__fake_rtable;
- dst_hold(skb->dst);
+ skb->rtable = &__fake_rtable;
+ dst_hold(&__fake_rtable.u.dst);
}
skb->dev = nf_bridge->physindev;
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- if (skb->dst == (struct dst_entry *)&__fake_rtable) {
- dst_release(skb->dst);
- skb->dst = NULL;
+ if (skb->rtable == &__fake_rtable) {
+ dst_release(&__fake_rtable.u.dst);
+ skb->rtable = NULL;
}
return NF_ACCEPT;
err = sysfs_create_group(brobj, &bridge_group);
if (err) {
pr_info("%s: can't create group %s/%s\n",
- __FUNCTION__, dev->name, bridge_group.name);
+ __func__, dev->name, bridge_group.name);
goto out1;
}
err = sysfs_create_bin_file(brobj, &bridge_forward);
if (err) {
pr_info("%s: can't create attribute file %s/%s\n",
- __FUNCTION__, dev->name, bridge_forward.attr.name);
+ __func__, dev->name, bridge_forward.attr.name);
goto out2;
}
br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj);
if (!br->ifobj) {
pr_info("%s: can't add kobject (directory) %s/%s\n",
- __FUNCTION__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
+ __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
goto out3;
}
return 0;
EXPORT_SYMBOL(dev_mc_unsync);
#ifdef CONFIG_PROC_FS
-static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(dev_base_lock)
-{
- struct net *net = seq_file_net(seq);
- struct net_device *dev;
- loff_t off = 0;
-
- read_lock(&dev_base_lock);
- for_each_netdev(net, dev) {
- if (off++ == *pos)
- return dev;
- }
- return NULL;
-}
-
-static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
- return next_net_device((struct net_device *)v);
-}
-
-static void dev_mc_seq_stop(struct seq_file *seq, void *v)
- __releases(dev_base_lock)
-{
- read_unlock(&dev_base_lock);
-}
-
-
static int dev_mc_seq_show(struct seq_file *seq, void *v)
{
struct dev_addr_list *m;
struct net_device *dev = v;
+ if (v == SEQ_START_TOKEN)
+ return 0;
+
netif_tx_lock_bh(dev);
for (m = dev->mc_list; m; m = m->next) {
int i;
}
static const struct seq_operations dev_mc_seq_ops = {
- .start = dev_mc_seq_start,
- .next = dev_mc_seq_next,
- .stop = dev_mc_seq_stop,
+ .start = dev_seq_start,
+ .next = dev_seq_next,
+ .stop = dev_seq_stop,
.show = dev_mc_seq_show,
};
struct net_device *dev = ptr;
struct dst_entry *dst, *last = NULL;
- if (dev->nd_net != &init_net)
- return NOTIFY_DONE;
-
switch (event) {
case NETDEV_UNREGISTER:
case NETDEV_DOWN:
struct neigh_parms *p;
for (p = &tbl->parms; p; p = p->next) {
- if (p->net != net)
- continue;
- if ((p->dev && p->dev->ifindex == ifindex) ||
+ if ((p->dev && p->dev->ifindex == ifindex && p->net == net) ||
(!p->dev && !ifindex))
return p;
}
neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
neigh_path[NEIGH_CTL_PATH_PROTO].ctl_name = p_id;
- t->sysctl_header = register_sysctl_paths(neigh_path, t->neigh_vars);
+ t->sysctl_header =
+ register_net_sysctl_table(p->net, neigh_path, t->neigh_vars);
if (!t->sysctl_header)
goto free_procname;
if (skb->dev->flags & IFF_NOARP)
return;
- if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
- (2 * skb->dev->addr_len) +
- (2 * sizeof(u32)))))
+ if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
return;
skb_reset_network_header(skb);
ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
return;
- size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4);
+ size = arp_hdr_len(skb->dev);
send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev),
LL_RESERVED_SPACE(np->dev));
if (atomic_read(&sk->sk_omem_alloc))
printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
- __FUNCTION__, atomic_read(&sk->sk_omem_alloc));
+ __func__, atomic_read(&sk->sk_omem_alloc));
put_net(sk->sk_net);
sk_prot_free(sk->sk_prot_creator, sk);
}
+/*
+ * Last sock_put should drop referrence to sk->sk_net. It has already
+ * been dropped in sk_change_net. Taking referrence to stopping namespace
+ * is not an option.
+ * Take referrence to a socket to remove it from hash _alive_ and after that
+ * destroy it in the context of init_net.
+ */
+void sk_release_kernel(struct sock *sk)
+{
+ if (sk == NULL || sk->sk_socket == NULL)
+ return;
+
+ sock_hold(sk);
+ sock_release(sk->sk_socket);
+ sk->sk_net = get_net(&init_net);
+ sock_put(sk);
+}
+EXPORT_SYMBOL(sk_release_kernel);
+
struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
{
struct sock *newsk;
* DCCP - specific warning and debugging macros.
*/
#define DCCP_WARN(fmt, a...) LIMIT_NETDEBUG(KERN_WARNING "%s: " fmt, \
- __FUNCTION__, ##a)
+ __func__, ##a)
#define DCCP_CRIT(fmt, a...) printk(KERN_CRIT fmt " at %s:%d/%s()\n", ##a, \
- __FILE__, __LINE__, __FUNCTION__)
+ __FILE__, __LINE__, __func__)
#define DCCP_BUG(a...) do { DCCP_CRIT("BUG: " a); dump_stack(); } while(0)
#define DCCP_BUG_ON(cond) do { if (unlikely((cond) != 0)) \
DCCP_BUG("\"%s\" holds (exception!)", \
printk(fmt, ##args); \
} while(0)
#define DCCP_PR_DEBUG(enable, fmt, a...) DCCP_PRINTK(enable, KERN_DEBUG \
- "%s: " fmt, __FUNCTION__, ##a)
+ "%s: " fmt, __func__, ##a)
#ifdef CONFIG_IP_DCCP_DEBUG
extern int dccp_debug;
struct sk_buff *skb)
{
struct rtable *rt;
- struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif,
+ struct flowi fl = { .oif = skb->rtable->rt_iif,
.nl_u = { .ip4_u =
{ .daddr = ip_hdr(skb)->saddr,
.saddr = ip_hdr(skb)->daddr,
return &rt->u.dst;
}
-static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
- struct dst_entry *dst)
+static int dccp_v4_send_response(struct sock *sk, struct request_sock *req)
{
int err = -1;
struct sk_buff *skb;
+ struct dst_entry *dst;
- /* First, grab a route. */
-
- if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL)
+ dst = inet_csk_route_req(sk, req);
+ if (dst == NULL)
goto out;
skb = dccp_make_response(sk, dst, req);
if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
return;
- if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
+ if (rxskb->rtable->rt_type != RTN_LOCAL)
return;
dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb);
struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
/* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
- if (((struct rtable *)skb->dst)->rt_flags &
- (RTCF_BROADCAST | RTCF_MULTICAST))
+ if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
return 0; /* discard, don't send a reset here */
if (dccp_bad_service_code(sk, service)) {
dreq->dreq_iss = dccp_v4_init_sequence(skb);
dreq->dreq_service = service;
- if (dccp_v4_send_response(sk, req, NULL))
+ if (dccp_v4_send_response(sk, req))
goto drop_and_free;
inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
}
-static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
- struct dst_entry *dst)
+static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
{
struct inet6_request_sock *ireq6 = inet6_rsk(req);
struct ipv6_pinfo *np = inet6_sk(sk);
struct in6_addr *final_p = NULL, final;
struct flowi fl;
int err = -1;
+ struct dst_entry *dst;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_DCCP;
fl.fl_ip_sport = inet_sk(sk)->sport;
security_req_classify_flow(req, &fl);
- if (dst == NULL) {
- opt = np->opt;
+ opt = np->opt;
- if (opt != NULL && opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
+ if (opt != NULL && opt->srcrt != NULL) {
+ const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ ipv6_addr_copy(&final, &fl.fl6_dst);
+ ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+ final_p = &final;
+ }
- err = ip6_dst_lookup(sk, &dst, &fl);
- if (err)
- goto done;
+ err = ip6_dst_lookup(sk, &dst, &fl);
+ if (err)
+ goto done;
- if (final_p)
- ipv6_addr_copy(&fl.fl6_dst, final_p);
+ if (final_p)
+ ipv6_addr_copy(&fl.fl6_dst, final_p);
- err = xfrm_lookup(&dst, &fl, sk, 0);
- if (err < 0)
- goto done;
- }
+ err = xfrm_lookup(&dst, &fl, sk, 0);
+ if (err < 0)
+ goto done;
skb = dccp_make_response(sk, dst, req);
if (skb != NULL) {
dreq->dreq_iss = dccp_v6_init_sequence(skb);
dreq->dreq_service = service;
- if (dccp_v6_send_response(sk, req, NULL))
+ if (dccp_v6_send_response(sk, req))
goto drop_and_free;
inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
* counter (backoff, monitored by dccp_response_timer).
*/
req->retrans++;
- req->rsk_ops->rtx_syn_ack(sk, req, NULL);
+ req->rsk_ops->rtx_syn_ack(sk, req);
}
/* Network Duplicate, discard packet */
return NULL;
static int dn_socket_seq_open(struct inode *inode, struct file *file)
{
- struct seq_file *seq;
- int rc = -ENOMEM;
- struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
- if (!s)
- goto out;
-
- rc = seq_open(file, &dn_socket_seq_ops);
- if (rc)
- goto out_kfree;
-
- seq = file->private_data;
- seq->private = s;
- memset(s, 0, sizeof(*s));
-out:
- return rc;
-out_kfree:
- kfree(s);
- goto out;
+ return seq_open_private(file, &dn_socket_seq_ops,
+ sizeof(struct dn_iter_state));
}
static const struct file_operations dn_socket_seq_fops = {
This can be compiled as a module and it will be called
"ieee80211_crypt_tkip".
-source "net/ieee80211/softmac/Kconfig"
ieee80211_wx.o \
ieee80211_geo.o
-obj-$(CONFIG_IEEE80211_SOFTMAC) += softmac/
+++ /dev/null
-config IEEE80211_SOFTMAC
- tristate "Software MAC add-on to the IEEE 802.11 networking stack"
- depends on IEEE80211 && EXPERIMENTAL
- select WIRELESS_EXT
- select IEEE80211_CRYPT_WEP
- ---help---
- This option enables the hardware independent software MAC addon
- for the IEEE 802.11 networking stack.
-
-config IEEE80211_SOFTMAC_DEBUG
- bool "Enable full debugging output"
- depends on IEEE80211_SOFTMAC
+++ /dev/null
-obj-$(CONFIG_IEEE80211_SOFTMAC) += ieee80211softmac.o
-ieee80211softmac-objs := \
- ieee80211softmac_io.o \
- ieee80211softmac_auth.o \
- ieee80211softmac_module.o \
- ieee80211softmac_scan.o \
- ieee80211softmac_wx.o \
- ieee80211softmac_assoc.o \
- ieee80211softmac_event.o
+++ /dev/null
-/*
- * This file contains the softmac's association logic.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-
-/*
- * Overview
- *
- * Before you can associate, you have to authenticate.
- *
- */
-
-/* Sends out an association request to the desired AP */
-static void
-ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
-{
- unsigned long flags;
-
- /* Switch to correct channel for this network */
- mac->set_channel(mac->dev, net->channel);
-
- /* Send association request */
- ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0);
-
- dprintk(KERN_INFO PFX "sent association request!\n");
-
- spin_lock_irqsave(&mac->lock, flags);
- mac->associnfo.associated = 0; /* just to make sure */
-
- /* Set a timer for timeout */
- /* FIXME: make timeout configurable */
- if (likely(mac->running))
- queue_delayed_work(mac->wq, &mac->associnfo.timeout, 5 * HZ);
- spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-void
-ieee80211softmac_assoc_timeout(struct work_struct *work)
-{
- struct ieee80211softmac_device *mac =
- container_of(work, struct ieee80211softmac_device,
- associnfo.timeout.work);
- struct ieee80211softmac_network *n;
-
- mutex_lock(&mac->associnfo.mutex);
- /* we might race against ieee80211softmac_handle_assoc_response,
- * so make sure only one of us does something */
- if (!mac->associnfo.associating)
- goto out;
- mac->associnfo.associating = 0;
- mac->associnfo.bssvalid = 0;
- mac->associnfo.associated = 0;
-
- n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
-
- dprintk(KERN_INFO PFX "assoc request timed out!\n");
- ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
-out:
- mutex_unlock(&mac->associnfo.mutex);
-}
-
-void
-ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mac->lock, flags);
- if (mac->associnfo.associating)
- cancel_delayed_work(&mac->associnfo.timeout);
-
- netif_carrier_off(mac->dev);
-
- mac->associnfo.associated = 0;
- mac->associnfo.bssvalid = 0;
- mac->associnfo.associating = 0;
- ieee80211softmac_init_bss(mac);
- ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
- spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-/* Sends out a disassociation request to the desired AP */
-void
-ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason)
-{
- struct ieee80211softmac_network *found;
-
- if (mac->associnfo.bssvalid && mac->associnfo.associated) {
- found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
- if (found)
- ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
- }
-
- ieee80211softmac_disassoc(mac);
-}
-
-static inline int
-we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
-{
- int idx;
- u8 rate;
-
- for (idx = 0; idx < (from_len); idx++) {
- rate = (from)[idx];
- if (!(rate & IEEE80211_BASIC_RATE_MASK))
- continue;
- rate &= ~IEEE80211_BASIC_RATE_MASK;
- if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
- return 0;
- }
- return 1;
-}
-
-static int
-network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
-{
- /* we cannot associate to networks whose name we don't know */
- if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
- return 0;
- /* do not associate to a network whose BSSBasicRateSet we cannot support */
- if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
- return 0;
- /* do we really need to check the ex rates? */
- if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
- return 0;
-
- /* assume that users know what they're doing ...
- * (note we don't let them select a net we're incompatible with) */
- if (mac->associnfo.bssfixed) {
- return !memcmp(mac->associnfo.bssid, net->bssid, ETH_ALEN);
- }
-
- /* if 'ANY' network requested, take any that doesn't have privacy enabled */
- if (mac->associnfo.req_essid.len == 0
- && !(net->capability & WLAN_CAPABILITY_PRIVACY))
- return 1;
- if (net->ssid_len != mac->associnfo.req_essid.len)
- return 0;
- if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
- return 1;
- return 0;
-}
-
-static void
-ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- ieee80211softmac_assoc_work(&mac->associnfo.work.work);
-}
-
-static void
-ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
- switch (event_type) {
- case IEEE80211SOFTMAC_EVENT_AUTHENTICATED:
- ieee80211softmac_assoc_work(&mac->associnfo.work.work);
- break;
- case IEEE80211SOFTMAC_EVENT_AUTH_FAILED:
- case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT:
- ieee80211softmac_disassoc(mac);
- break;
- }
-}
-
-/* This function is called to handle userspace requests (asynchronously) */
-void
-ieee80211softmac_assoc_work(struct work_struct *work)
-{
- struct ieee80211softmac_device *mac =
- container_of(work, struct ieee80211softmac_device,
- associnfo.work.work);
- struct ieee80211softmac_network *found = NULL;
- struct ieee80211_network *net = NULL, *best = NULL;
- int bssvalid;
- unsigned long flags;
-
- mutex_lock(&mac->associnfo.mutex);
-
- if (!mac->associnfo.associating)
- goto out;
-
- /* ieee80211_disassoc might clear this */
- bssvalid = mac->associnfo.bssvalid;
-
- /* meh */
- if (mac->associnfo.associated)
- ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
-
- /* try to find the requested network in our list, if we found one already */
- if (bssvalid || mac->associnfo.bssfixed)
- found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
-
- /* Search the ieee80211 networks for this network if we didn't find it by bssid,
- * but only if we've scanned at least once (to get a better list of networks to
- * select from). If we have not scanned before, the !found logic below will be
- * invoked and will scan. */
- if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT))
- {
- s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning
- because it cannot follow the best pointer logic. */
- spin_lock_irqsave(&mac->ieee->lock, flags);
- list_for_each_entry(net, &mac->ieee->network_list, list) {
- /* we're supposed to find the network with
- * the best signal here, as we're asked to join
- * any network with a specific ESSID, and many
- * different ones could have that.
- *
- * I'll for now just go with the reported rssi.
- *
- * We also should take into account the rateset
- * here to find the best BSSID to try.
- */
- if (network_matches_request(mac, net)) {
- if (!best) {
- best = net;
- rssi = best->stats.rssi;
- continue;
- }
- /* we already had a matching network, so
- * compare their properties to get the
- * better of the two ... (see above)
- */
- if (rssi < net->stats.rssi) {
- best = net;
- rssi = best->stats.rssi;
- }
- }
- }
- /* if we unlock here, we might get interrupted and the `best'
- * pointer could go stale */
- if (best) {
- found = ieee80211softmac_create_network(mac, best);
- /* if found is still NULL, then we got -ENOMEM somewhere */
- if (found)
- ieee80211softmac_add_network(mac, found);
- }
- spin_unlock_irqrestore(&mac->ieee->lock, flags);
- }
-
- if (!found) {
- if (mac->associnfo.scan_retry > 0) {
- mac->associnfo.scan_retry--;
-
- /* We know of no such network. Let's scan.
- * NB: this also happens if we had no memory to copy the network info...
- * Maybe we can hope to have more memory after scanning finishes ;)
- */
- dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
- ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
- if (ieee80211softmac_start_scan(mac)) {
- dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
- }
- goto out;
- } else {
- mac->associnfo.associating = 0;
- mac->associnfo.associated = 0;
-
- dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
- /* reset the retry counter for the next user request since we
- * break out and don't reschedule ourselves after this point. */
- mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
- ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
- goto out;
- }
- }
-
- /* reset the retry counter for the next user request since we
- * now found a net and will try to associate to it, but not
- * schedule this function again. */
- mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
- mac->associnfo.bssvalid = 1;
- memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
- /* copy the ESSID for displaying it */
- mac->associnfo.associate_essid.len = found->essid.len;
- memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
-
- /* we found a network! authenticate (if necessary) and associate to it. */
- if (found->authenticating) {
- dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
- if(!mac->associnfo.assoc_wait) {
- mac->associnfo.assoc_wait = 1;
- ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
- }
- goto out;
- }
- if (!found->authenticated && !found->authenticating) {
- /* This relies on the fact that _auth_req only queues the work,
- * otherwise adding the notification would be racy. */
- if (!ieee80211softmac_auth_req(mac, found)) {
- if(!mac->associnfo.assoc_wait) {
- dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
- mac->associnfo.assoc_wait = 1;
- ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
- }
- } else {
- printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
- mac->associnfo.assoc_wait = 0;
- ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
- }
- goto out;
- }
- /* finally! now we can start associating */
- mac->associnfo.assoc_wait = 0;
- ieee80211softmac_assoc(mac, found);
-
-out:
- mutex_unlock(&mac->associnfo.mutex);
-}
-
-/* call this to do whatever is necessary when we're associated */
-static void
-ieee80211softmac_associated(struct ieee80211softmac_device *mac,
- struct ieee80211_assoc_response * resp,
- struct ieee80211softmac_network *net)
-{
- u16 cap = le16_to_cpu(resp->capability);
- u8 erp_value = net->erp_value;
-
- mac->associnfo.associating = 0;
- mac->bssinfo.supported_rates = net->supported_rates;
- ieee80211softmac_recalc_txrates(mac);
-
- mac->associnfo.associated = 1;
-
- mac->associnfo.short_preamble_available =
- (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
- ieee80211softmac_process_erp(mac, erp_value);
-
- if (mac->set_bssid_filter)
- mac->set_bssid_filter(mac->dev, net->bssid);
- memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
- netif_carrier_on(mac->dev);
-
- mac->association_id = le16_to_cpup(&resp->aid);
-}
-
-/* received frame handling functions */
-int
-ieee80211softmac_handle_assoc_response(struct net_device * dev,
- struct ieee80211_assoc_response * resp,
- struct ieee80211_network * _ieee80211_network)
-{
- /* NOTE: the network parameter has to be mostly ignored by
- * this code because it is the ieee80211's pointer
- * to the struct, not ours (we made a copy)
- */
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- u16 status = le16_to_cpup(&resp->status);
- struct ieee80211softmac_network *network = NULL;
- unsigned long flags;
- DECLARE_MAC_BUF(mac2);
-
- if (unlikely(!mac->running))
- return -ENODEV;
-
- spin_lock_irqsave(&mac->lock, flags);
-
- if (!mac->associnfo.associating) {
- /* we race against the timeout function, so make sure
- * only one of us can do work */
- spin_unlock_irqrestore(&mac->lock, flags);
- return 0;
- }
- network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
-
- /* someone sending us things without us knowing him? Ignore. */
- if (!network) {
- dprintk(KERN_INFO PFX "Received unrequested assocation response from %s\n",
- print_mac(mac2, resp->header.addr3));
- spin_unlock_irqrestore(&mac->lock, flags);
- return 0;
- }
-
- /* now that we know it was for us, we can cancel the timeout */
- cancel_delayed_work(&mac->associnfo.timeout);
-
- /* if the association response included an ERP IE, update our saved
- * copy */
- if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
- network->erp_value = _ieee80211_network->erp_value;
-
- switch (status) {
- case 0:
- dprintk(KERN_INFO PFX "associated!\n");
- ieee80211softmac_associated(mac, resp, network);
- ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
- break;
- case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
- if (!network->auth_desynced_once) {
- /* there seem to be a few rare cases where our view of
- * the world is obscured, or buggy APs that don't DEAUTH
- * us properly. So we handle that, but allow it only once.
- */
- printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
- network->authenticated = 0;
- /* we don't want to do this more than once ... */
- network->auth_desynced_once = 1;
- queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
- break;
- }
- default:
- dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
- mac->associnfo.associating = 0;
- mac->associnfo.bssvalid = 0;
- mac->associnfo.associated = 0;
- ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
- }
-
- spin_unlock_irqrestore(&mac->lock, flags);
- return 0;
-}
-
-void
-ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mac->lock, flags);
- mac->associnfo.associating = 1;
- queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
- spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-int
-ieee80211softmac_handle_disassoc(struct net_device * dev,
- struct ieee80211_disassoc *disassoc)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
- if (unlikely(!mac->running))
- return -ENODEV;
-
- if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
- return 0;
-
- if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
- return 0;
-
- dprintk(KERN_INFO PFX "got disassoc frame\n");
- ieee80211softmac_disassoc(mac);
-
- ieee80211softmac_try_reassoc(mac);
-
- return 0;
-}
-
-int
-ieee80211softmac_handle_reassoc_req(struct net_device * dev,
- struct ieee80211_reassoc_request * resp)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- struct ieee80211softmac_network *network;
-
- if (unlikely(!mac->running))
- return -ENODEV;
-
- network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
- if (!network) {
- dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
- return 0;
- }
- queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
-
- return 0;
-}
+++ /dev/null
-/*
- * This file contains the softmac's authentication logic.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-
-static void ieee80211softmac_auth_queue(struct work_struct *work);
-
-/* Queues an auth request to the desired AP */
-int
-ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *net)
-{
- struct ieee80211softmac_auth_queue_item *auth;
- unsigned long flags;
- DECLARE_MAC_BUF(mac2);
-
- if (net->authenticating || net->authenticated)
- return 0;
- net->authenticating = 1;
-
- /* Add the network if it's not already added */
- ieee80211softmac_add_network(mac, net);
-
- dprintk(KERN_NOTICE PFX "Queueing Authentication Request to %s\n", print_mac(mac2, net->bssid));
- /* Queue the auth request */
- auth = (struct ieee80211softmac_auth_queue_item *)
- kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
- if(auth == NULL)
- return -ENOMEM;
-
- auth->net = net;
- auth->mac = mac;
- auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
- auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
- INIT_DELAYED_WORK(&auth->work, ieee80211softmac_auth_queue);
-
- /* Lock (for list) */
- spin_lock_irqsave(&mac->lock, flags);
-
- /* add to list */
- list_add_tail(&auth->list, &mac->auth_queue);
- queue_delayed_work(mac->wq, &auth->work, 0);
- spin_unlock_irqrestore(&mac->lock, flags);
-
- return 0;
-}
-
-
-/* Sends an auth request to the desired AP and handles timeouts */
-static void
-ieee80211softmac_auth_queue(struct work_struct *work)
-{
- struct ieee80211softmac_device *mac;
- struct ieee80211softmac_auth_queue_item *auth;
- struct ieee80211softmac_network *net;
- unsigned long flags;
- DECLARE_MAC_BUF(mac2);
-
- auth = container_of(work, struct ieee80211softmac_auth_queue_item,
- work.work);
- net = auth->net;
- mac = auth->mac;
-
- if(auth->retry > 0) {
- /* Switch to correct channel for this network */
- mac->set_channel(mac->dev, net->channel);
-
- /* Lock and set flags */
- spin_lock_irqsave(&mac->lock, flags);
- if (unlikely(!mac->running)) {
- /* Prevent reschedule on workqueue flush */
- spin_unlock_irqrestore(&mac->lock, flags);
- return;
- }
- net->authenticated = 0;
- /* add a timeout call so we eventually give up waiting for an auth reply */
- queue_delayed_work(mac->wq, &auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
- auth->retry--;
- spin_unlock_irqrestore(&mac->lock, flags);
- if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
- dprintk(KERN_NOTICE PFX "Sending Authentication Request to %s failed (this shouldn't happen, wait for the timeout).\n",
- print_mac(mac2, net->bssid));
- else
- dprintk(KERN_NOTICE PFX "Sent Authentication Request to %s.\n", print_mac(mac2, net->bssid));
- return;
- }
-
- printkl(KERN_WARNING PFX "Authentication timed out with %s\n", print_mac(mac2, net->bssid));
- /* Remove this item from the queue */
- spin_lock_irqsave(&mac->lock, flags);
- net->authenticating = 0;
- ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
- cancel_delayed_work(&auth->work); /* just to make sure... */
- list_del(&auth->list);
- spin_unlock_irqrestore(&mac->lock, flags);
- /* Free it */
- kfree(auth);
-}
-
-/* Sends a response to an auth challenge (for shared key auth). */
-static void
-ieee80211softmac_auth_challenge_response(struct work_struct *work)
-{
- struct ieee80211softmac_auth_queue_item *aq =
- container_of(work, struct ieee80211softmac_auth_queue_item,
- work.work);
-
- /* Send our response */
- ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
-}
-
-/* Handle the auth response from the AP
- * This should be registered with ieee80211 as handle_auth
- */
-int
-ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
-{
-
- struct list_head *list_ptr;
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- struct ieee80211softmac_auth_queue_item *aq = NULL;
- struct ieee80211softmac_network *net = NULL;
- unsigned long flags;
- u8 * data;
- DECLARE_MAC_BUF(mac2);
-
- if (unlikely(!mac->running))
- return -ENODEV;
-
- /* Find correct auth queue item */
- spin_lock_irqsave(&mac->lock, flags);
- list_for_each(list_ptr, &mac->auth_queue) {
- aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
- net = aq->net;
- if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
- break;
- else
- aq = NULL;
- }
- spin_unlock_irqrestore(&mac->lock, flags);
-
- /* Make sure that we've got an auth queue item for this request */
- if(aq == NULL)
- {
- dprintkl(KERN_DEBUG PFX "Authentication response received from %s but no queue item exists.\n", print_mac(mac2, auth->header.addr2));
- /* Error #? */
- return -1;
- }
-
- /* Check for out of order authentication */
- if(!net->authenticating)
- {
- dprintkl(KERN_DEBUG PFX "Authentication response received from %s but did not request authentication.\n",print_mac(mac2, auth->header.addr2));
- return -1;
- }
-
- /* Parse the auth packet */
- switch(le16_to_cpu(auth->algorithm)) {
- case WLAN_AUTH_OPEN:
- /* Check the status code of the response */
-
- switch(le16_to_cpu(auth->status)) {
- case WLAN_STATUS_SUCCESS:
- /* Update the status to Authenticated */
- spin_lock_irqsave(&mac->lock, flags);
- net->authenticating = 0;
- net->authenticated = 1;
- spin_unlock_irqrestore(&mac->lock, flags);
-
- /* Send event */
- printkl(KERN_NOTICE PFX "Open Authentication completed with %s\n", print_mac(mac2, net->bssid));
- ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
- break;
- default:
- /* Lock and reset flags */
- spin_lock_irqsave(&mac->lock, flags);
- net->authenticated = 0;
- net->authenticating = 0;
- spin_unlock_irqrestore(&mac->lock, flags);
-
- printkl(KERN_NOTICE PFX "Open Authentication with %s failed, error code: %i\n",
- print_mac(mac2, net->bssid), le16_to_cpup(&auth->status));
- /* Count the error? */
- break;
- }
- goto free_aq;
- break;
- case WLAN_AUTH_SHARED_KEY:
- /* Figure out where we are in the process */
- switch(le16_to_cpu(auth->transaction)) {
- case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
- /* Check to make sure we have a challenge IE */
- data = (u8 *)auth->info_element;
- if (*data++ != MFIE_TYPE_CHALLENGE) {
- printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
- break;
- }
- /* Save the challenge */
- spin_lock_irqsave(&mac->lock, flags);
- net->challenge_len = *data++;
- if (net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
- net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
- kfree(net->challenge);
- net->challenge = kmemdup(data, net->challenge_len,
- GFP_ATOMIC);
- if (net->challenge == NULL) {
- printkl(KERN_NOTICE PFX "Shared Key "
- "Authentication failed due to "
- "memory shortage.\n");
- spin_unlock_irqrestore(&mac->lock, flags);
- break;
- }
- aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
-
- /* We reuse the work struct from the auth request here.
- * It is safe to do so as each one is per-request, and
- * at this point (dealing with authentication response)
- * we have obviously already sent the initial auth
- * request. */
- cancel_delayed_work(&aq->work);
- INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response);
- queue_delayed_work(mac->wq, &aq->work, 0);
- spin_unlock_irqrestore(&mac->lock, flags);
- return 0;
- case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
- kfree(net->challenge);
- net->challenge = NULL;
- net->challenge_len = 0;
- /* Check the status code of the response */
- switch(auth->status) {
- case WLAN_STATUS_SUCCESS:
- /* Update the status to Authenticated */
- spin_lock_irqsave(&mac->lock, flags);
- net->authenticating = 0;
- net->authenticated = 1;
- spin_unlock_irqrestore(&mac->lock, flags);
- printkl(KERN_NOTICE PFX "Shared Key Authentication completed with %s\n",
- print_mac(mac2, net->bssid));
- ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
- break;
- default:
- printkl(KERN_NOTICE PFX "Shared Key Authentication with %s failed, error code: %i\n",
- print_mac(mac2, net->bssid), le16_to_cpup(&auth->status));
- /* Lock and reset flags */
- spin_lock_irqsave(&mac->lock, flags);
- net->authenticating = 0;
- net->authenticated = 0;
- spin_unlock_irqrestore(&mac->lock, flags);
- /* Count the error? */
- break;
- }
- goto free_aq;
- break;
- default:
- printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
- break;
- }
- goto free_aq;
- break;
- default:
- /* ERROR */
- goto free_aq;
- break;
- }
- return 0;
-free_aq:
- /* Cancel the timeout */
- spin_lock_irqsave(&mac->lock, flags);
- cancel_delayed_work(&aq->work);
- /* Remove this item from the queue */
- list_del(&aq->list);
- spin_unlock_irqrestore(&mac->lock, flags);
-
- /* Free it */
- kfree(aq);
- return 0;
-}
-
-/*
- * Handle deauthorization
- */
-static void
-ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *net)
-{
- struct ieee80211softmac_auth_queue_item *aq = NULL;
- struct list_head *list_ptr;
- unsigned long flags;
-
- /* deauthentication implies disassociation */
- ieee80211softmac_disassoc(mac);
-
- /* Lock and reset status flags */
- spin_lock_irqsave(&mac->lock, flags);
- net->authenticating = 0;
- net->authenticated = 0;
-
- /* Find correct auth queue item, if it exists */
- list_for_each(list_ptr, &mac->auth_queue) {
- aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
- if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
- break;
- else
- aq = NULL;
- }
-
- /* Cancel pending work */
- if(aq != NULL)
- /* Not entirely safe? What about running work? */
- cancel_delayed_work(&aq->work);
-
- /* Free our network ref */
- ieee80211softmac_del_network_locked(mac, net);
- if(net->challenge != NULL)
- kfree(net->challenge);
- kfree(net);
-
- /* can't transmit data right now... */
- netif_carrier_off(mac->dev);
- spin_unlock_irqrestore(&mac->lock, flags);
-
- ieee80211softmac_try_reassoc(mac);
-}
-
-/*
- * Sends a deauth request to the desired AP
- */
-int
-ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *net, int reason)
-{
- int ret;
-
- /* Make sure the network is authenticated */
- if (!net->authenticated)
- {
- dprintkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
- /* Error okay? */
- return -EPERM;
- }
-
- /* Send the de-auth packet */
- if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
- return ret;
-
- ieee80211softmac_deauth_from_net(mac, net);
- return 0;
-}
-
-/*
- * This should be registered with ieee80211 as handle_deauth
- */
-int
-ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth)
-{
-
- struct ieee80211softmac_network *net = NULL;
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- DECLARE_MAC_BUF(mac2);
-
- if (unlikely(!mac->running))
- return -ENODEV;
-
- if (!deauth) {
- dprintk("deauth without deauth packet. eek!\n");
- return 0;
- }
-
- net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2);
-
- if (net == NULL) {
- dprintkl(KERN_DEBUG PFX "Received deauthentication packet from %s, but that network is unknown.\n",
- print_mac(mac2, deauth->header.addr2));
- return 0;
- }
-
- /* Make sure the network is authenticated */
- if(!net->authenticated)
- {
- dprintkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
- /* Error okay? */
- return -EPERM;
- }
-
- ieee80211softmac_deauth_from_net(mac, net);
-
- /* let's try to re-associate */
- queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
- return 0;
-}
+++ /dev/null
-/*
- * Event system
- * Also see comments in public header file and longer explanation below.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-
-/*
- * Each event has associated to it
- * - an event type (see constants in public header)
- * - an event context (see below)
- * - the function to be called
- * - a context (extra parameter to call the function with)
- * - and the softmac struct
- *
- * The event context is private and can only be used from
- * within this module. Its meaning varies with the event
- * type:
- * SCAN_FINISHED,
- * DISASSOCIATED: NULL
- * ASSOCIATED,
- * ASSOCIATE_FAILED,
- * ASSOCIATE_TIMEOUT,
- * AUTHENTICATED,
- * AUTH_FAILED,
- * AUTH_TIMEOUT: a pointer to the network struct
- * ...
- * Code within this module can use the event context to be only
- * called when the event is true for that specific context
- * as per above table.
- * If the event context is NULL, then the notification is always called,
- * regardless of the event context. The event context is not passed to
- * the callback, it is assumed that the context suffices.
- *
- * You can also use the event context only by setting the event type
- * to -1 (private use only), in which case you'll be notified
- * whenever the event context matches.
- */
-
-static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
- NULL, /* scan finished */
- NULL, /* associated */
- "associating failed",
- "associating timed out",
- "authenticated",
- "authenticating failed",
- "authenticating timed out",
- "associating failed because no suitable network was found",
- NULL, /* disassociated */
-};
-
-
-static void
-ieee80211softmac_notify_callback(struct work_struct *work)
-{
- struct ieee80211softmac_event *pevent =
- container_of(work, struct ieee80211softmac_event, work.work);
- struct ieee80211softmac_event event = *pevent;
- kfree(pevent);
-
- event.fun(event.mac->dev, event.event_type, event.context);
-}
-
-int
-ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
- int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
-{
- struct ieee80211softmac_event *eventptr;
- unsigned long flags;
-
- if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
- return -ENOSYS;
-
- if (!fun)
- return -EINVAL;
-
- eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
- if (!eventptr)
- return -ENOMEM;
-
- eventptr->event_type = event;
- INIT_DELAYED_WORK(&eventptr->work, ieee80211softmac_notify_callback);
- eventptr->fun = fun;
- eventptr->context = context;
- eventptr->mac = mac;
- eventptr->event_context = event_context;
-
- spin_lock_irqsave(&mac->lock, flags);
- list_add(&eventptr->list, &mac->events);
- spin_unlock_irqrestore(&mac->lock, flags);
-
- return 0;
-}
-
-int
-ieee80211softmac_notify_gfp(struct net_device *dev,
- int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
- if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
- return -ENOSYS;
-
- return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
-
-/* private -- calling all callbacks that were specified */
-void
-ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
-{
- struct ieee80211softmac_event *eventptr, *tmp;
- struct ieee80211softmac_network *network;
-
- if (event >= 0) {
- union iwreq_data wrqu;
- int we_event;
- char *msg = NULL;
-
- memset(&wrqu, '\0', sizeof (union iwreq_data));
-
- switch(event) {
- case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
- network = (struct ieee80211softmac_network *)event_ctx;
- memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN);
- /* fall through */
- case IEEE80211SOFTMAC_EVENT_DISASSOCIATED:
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- we_event = SIOCGIWAP;
- break;
- case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
- we_event = SIOCGIWSCAN;
- break;
- default:
- msg = event_descriptions[event];
- if (!msg)
- msg = "SOFTMAC EVENT BUG";
- wrqu.data.length = strlen(msg);
- we_event = IWEVCUSTOM;
- break;
- }
- wireless_send_event(mac->dev, we_event, &wrqu, msg);
- }
-
- if (!list_empty(&mac->events))
- list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
- if ((eventptr->event_type == event || eventptr->event_type == -1)
- && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
- list_del(&eventptr->list);
- /* User may have subscribed to ANY event, so
- * we tell them which event triggered it. */
- eventptr->event_type = event;
- queue_delayed_work(mac->wq, &eventptr->work, 0);
- }
- }
-}
-
-void
-ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mac->lock, flags);
- ieee80211softmac_call_events_locked(mac, event, event_ctx);
-
- spin_unlock_irqrestore(&mac->lock, flags);
-}
+++ /dev/null
-/*
- * Some parts based on code from net80211
- * Copyright (c) 2001 Atsushi Onoe
- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "ieee80211softmac_priv.h"
-
-/* Helper functions for inserting data into the frames */
-
-/*
- * Adds an ESSID element to the frame
- *
- */
-static u8 *
-ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid)
-{
- if (essid) {
- *dst++ = MFIE_TYPE_SSID;
- *dst++ = essid->len;
- memcpy(dst, essid->data, essid->len);
- return dst+essid->len;
- } else {
- *dst++ = MFIE_TYPE_SSID;
- *dst++ = 0;
- return dst;
- }
-}
-
-/* Adds Supported Rates and if required Extended Rates Information Element
- * to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */
-static u8 *
-ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r)
-{
- int cck_len, ofdm_len;
- *dst++ = MFIE_TYPE_RATES;
-
- for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++);
-
- if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN)
- cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN;
- *dst++ = cck_len;
- memcpy(dst, r->rates, cck_len);
- dst += cck_len;
-
- if(cck_len < r->count){
- for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++);
- if (ofdm_len > 0) {
- if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN)
- ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN;
- *dst++ = MFIE_TYPE_RATES_EX;
- *dst++ = ofdm_len;
- memcpy(dst, r->rates + cck_len, ofdm_len);
- dst += ofdm_len;
- }
- }
- return dst;
-}
-
-/* Allocate a management frame */
-static u8 *
-ieee80211softmac_alloc_mgt(u32 size)
-{
- u8 * data;
-
- /* Add the header and FCS to the size */
- size = size + IEEE80211_3ADDR_LEN;
- if(size > IEEE80211_DATA_LEN)
- return NULL;
- /* Allocate the frame */
- data = kzalloc(size, GFP_ATOMIC);
- return data;
-}
-
-/*
- * Add a 2 Address Header
- */
-static void
-ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac,
- struct ieee80211_hdr_2addr *header, u32 type, u8 *dest)
-{
- /* Fill in the frame control flags */
- header->frame_ctl = cpu_to_le16(type);
- /* Control packets always have WEP turned off */
- if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL)
- header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0;
-
- /* Fill in the duration */
- header->duration_id = 0;
- /* FIXME: How do I find this?
- * calculate. But most drivers just fill in 0 (except if it's a station id of course) */
-
- /* Fill in the Destination Address */
- if(dest == NULL)
- memset(header->addr1, 0xFF, ETH_ALEN);
- else
- memcpy(header->addr1, dest, ETH_ALEN);
- /* Fill in the Source Address */
- memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN);
-
-}
-
-
-/* Add a 3 Address Header */
-static void
-ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
- struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid)
-{
- /* This is common with 2addr, so use that instead */
- ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest);
-
- /* Fill in the BSS ID */
- if(bssid == NULL)
- memset(header->addr3, 0xFF, ETH_ALEN);
- else
- memcpy(header->addr3, bssid, ETH_ALEN);
-
- /* Fill in the sequence # */
- /* FIXME: I need to add this to the softmac struct
- * shouldn't the sequence number be in ieee80211? */
-}
-
-static __le16
-ieee80211softmac_capabilities(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *net)
-{
- __le16 capability = 0;
-
- /* ESS and IBSS bits are set according to the current mode */
- switch (mac->ieee->iw_mode) {
- case IW_MODE_INFRA:
- capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
- break;
- case IW_MODE_ADHOC:
- capability = cpu_to_le16(WLAN_CAPABILITY_IBSS);
- break;
- case IW_MODE_AUTO:
- capability = cpu_to_le16(net->capabilities &
- (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS));
- break;
- default:
- /* bleh. we don't ever go to these modes */
- printk(KERN_ERR PFX "invalid iw_mode!\n");
- break;
- }
-
- /* CF Pollable / CF Poll Request */
- /* Needs to be implemented, for now, the 0's == not supported */
-
- /* Privacy Bit */
- capability |= mac->ieee->sec.level ?
- cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
-
- /* Short Preamble */
- /* Always supported: we probably won't ever be powering devices which
- * dont support this... */
- capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
-
- /* PBCC */
- /* Not widely used */
-
- /* Channel Agility */
- /* Not widely used */
-
- /* Short Slot */
- /* Will be implemented later */
-
- /* DSSS-OFDM */
- /* Not widely used */
-
- return capability;
-}
-
-/*****************************************************************************
- * Create Management packets
- *****************************************************************************/
-
-/* Creates an association request packet */
-static u32
-ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
- struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
-{
- u8 *data;
- (*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt(
- 2 + /* Capability Info */
- 2 + /* Listen Interval */
- /* SSID IE */
- 1 + 1 + IW_ESSID_MAX_SIZE +
- /* Rates IE */
- 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
- /* Extended Rates IE */
- 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN +
- /* WPA IE if present */
- mac->wpa.IElen
- /* Other IE's? Optional?
- * Yeah, probably need an extra IE parameter -- lots of vendors like to
- * fill in their own IEs */
- );
- if (unlikely((*pkt) == NULL))
- return 0;
- ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
-
- /* Fill in the capabilities */
- (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
-
- /* Fill in Listen Interval (?) */
- (*pkt)->listen_interval = cpu_to_le16(10);
-
- data = (u8 *)(*pkt)->info_element;
- /* Add SSID */
- data = ieee80211softmac_add_essid(data, &net->essid);
- /* Add Rates */
- data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
- /* Add WPA IE */
- if (mac->wpa.IElen && mac->wpa.IE) {
- memcpy(data, mac->wpa.IE, mac->wpa.IElen);
- data += mac->wpa.IElen;
- }
- /* Return the number of used bytes */
- return (data - (u8*)(*pkt));
-}
-
-/* Create a reassociation request packet */
-static u32
-ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
- struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
-{
- u8 *data;
- (*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt(
- 2 + /* Capability Info */
- 2 + /* Listen Interval */
- ETH_ALEN + /* AP MAC */
- /* SSID IE */
- 1 + 1 + IW_ESSID_MAX_SIZE +
- /* Rates IE */
- 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
- /* Extended Rates IE */
- 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
- /* Other IE's? */
- );
- if (unlikely((*pkt) == NULL))
- return 0;
- ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
-
- /* Fill in the capabilities */
- (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
-
- /* Fill in Listen Interval (?) */
- (*pkt)->listen_interval = cpu_to_le16(10);
- /* Fill in the current AP MAC */
- memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN);
-
- data = (u8 *)(*pkt)->info_element;
- /* Add SSID */
- data = ieee80211softmac_add_essid(data, &net->essid);
- /* Add Rates */
- data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
- /* Return packet size */
- return (data - (u8 *)(*pkt));
-}
-
-/* Create an authentication packet */
-static u32
-ieee80211softmac_auth(struct ieee80211_auth **pkt,
- struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
- u16 transaction, u16 status, int *encrypt_mpdu)
-{
- u8 *data;
- int auth_mode = mac->ieee->sec.auth_mode;
- int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY
- && transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE);
-
- /* Allocate Packet */
- (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
- 2 + /* Auth Algorithm */
- 2 + /* Auth Transaction Seq */
- 2 + /* Status Code */
- /* Challenge Text IE */
- (is_shared_response ? 1 + 1 + net->challenge_len : 0)
- );
- if (unlikely((*pkt) == NULL))
- return 0;
- ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
-
- /* Algorithm */
- (*pkt)->algorithm = cpu_to_le16(auth_mode);
- /* Transaction */
- (*pkt)->transaction = cpu_to_le16(transaction);
- /* Status */
- (*pkt)->status = cpu_to_le16(status);
-
- data = (u8 *)(*pkt)->info_element;
- /* Challenge Text */
- if (is_shared_response) {
- *data = MFIE_TYPE_CHALLENGE;
- data++;
-
- /* Copy the challenge in */
- *data = net->challenge_len;
- data++;
- memcpy(data, net->challenge, net->challenge_len);
- data += net->challenge_len;
-
- /* Make sure this frame gets encrypted with the shared key */
- *encrypt_mpdu = 1;
- } else
- *encrypt_mpdu = 0;
-
- /* Return the packet size */
- return (data - (u8 *)(*pkt));
-}
-
-/* Create a disassocation or deauthentication packet */
-static u32
-ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt,
- struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
- u16 type, u16 reason)
-{
- /* Allocate Packet */
- (*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2);
- if (unlikely((*pkt) == NULL))
- return 0;
- ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid);
- /* Reason */
- (*pkt)->reason = cpu_to_le16(reason);
- /* Return the packet size */
- return (2 + IEEE80211_3ADDR_LEN);
-}
-
-/* Create a probe request packet */
-static u32
-ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt,
- struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid)
-{
- u8 *data;
- /* Allocate Packet */
- (*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt(
- /* SSID of requested network */
- 1 + 1 + IW_ESSID_MAX_SIZE +
- /* Rates IE */
- 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
- /* Extended Rates IE */
- 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
- );
- if (unlikely((*pkt) == NULL))
- return 0;
- ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL);
-
- data = (u8 *)(*pkt)->info_element;
- /* Add ESSID (can be NULL) */
- data = ieee80211softmac_add_essid(data, essid);
- /* Add Rates */
- data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
- /* Return packet size */
- return (data - (u8 *)(*pkt));
-}
-
-/* Create a probe response packet */
-/* FIXME: Not complete */
-static u32
-ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt,
- struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
-{
- u8 *data;
- /* Allocate Packet */
- (*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt(
- 8 + /* Timestamp */
- 2 + /* Beacon Interval */
- 2 + /* Capability Info */
- /* SSID IE */
- 1 + 1 + IW_ESSID_MAX_SIZE +
- 7 + /* FH Parameter Set */
- 2 + /* DS Parameter Set */
- 8 + /* CF Parameter Set */
- 4 /* IBSS Parameter Set */
- );
- if (unlikely((*pkt) == NULL))
- return 0;
- ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid);
- data = (u8 *)(*pkt)->info_element;
-
- /* Return the packet size */
- return (data - (u8 *)(*pkt));
-}
-
-
-/* Sends a manangement packet
- * FIXME: document the use of the arg parameter
- * for _AUTH: (transaction #) | (status << 16)
- */
-int
-ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
- void *ptrarg, u32 type, u32 arg)
-{
- void *pkt = NULL;
- u32 pkt_size = 0;
- int encrypt_mpdu = 0;
-
- switch(type) {
- case IEEE80211_STYPE_ASSOC_REQ:
- pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
- break;
- case IEEE80211_STYPE_REASSOC_REQ:
- pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
- break;
- case IEEE80211_STYPE_AUTH:
- pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu);
- break;
- case IEEE80211_STYPE_DISASSOC:
- case IEEE80211_STYPE_DEAUTH:
- pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF));
- break;
- case IEEE80211_STYPE_PROBE_REQ:
- pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg);
- break;
- case IEEE80211_STYPE_PROBE_RESP:
- pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
- break;
- default:
- printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type);
- return -EINVAL;
- };
-
- if(pkt_size == 0 || pkt == NULL) {
- printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n");
- return -ENOMEM;
- }
-
- /* Send the packet to the ieee80211 layer for tx */
- /* we defined softmac->mgmt_xmit for this. Should we keep it
- * as it is (that means we'd need to wrap this into a txb),
- * modify the prototype (so it matches this function),
- * or get rid of it alltogether?
- * Does this work for you now?
- */
- ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt,
- IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu);
-
- kfree(pkt);
- return 0;
-}
-
-/* Beacon handling */
-int ieee80211softmac_handle_beacon(struct net_device *dev,
- struct ieee80211_beacon *beacon,
- struct ieee80211_network *network)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
- /* This might race, but we don't really care and it's not worth
- * adding heavyweight locking in this fastpath.
- */
- if (mac->associnfo.associated) {
- if (memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
- ieee80211softmac_process_erp(mac, network->erp_value);
- }
-
- return 0;
-}
-
+++ /dev/null
-/*
- * Contains some basic softmac functions along with module registration code etc.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-#include <linux/sort.h>
-#include <linux/etherdevice.h>
-
-struct net_device *alloc_ieee80211softmac(int sizeof_priv)
-{
- struct ieee80211softmac_device *softmac;
- struct net_device *dev;
-
- dev = alloc_ieee80211(sizeof(*softmac) + sizeof_priv);
- if (!dev)
- return NULL;
- softmac = ieee80211_priv(dev);
- softmac->wq = create_freezeable_workqueue("softmac");
- if (!softmac->wq) {
- free_ieee80211(dev);
- return NULL;
- }
-
- softmac->dev = dev;
- softmac->ieee = netdev_priv(dev);
- spin_lock_init(&softmac->lock);
-
- softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
- softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
- softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
- softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
- softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
- softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
- softmac->scaninfo = NULL;
-
- softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
-
- /* TODO: initialise all the other callbacks in the ieee struct
- * (once they're written)
- */
-
- INIT_LIST_HEAD(&softmac->auth_queue);
- INIT_LIST_HEAD(&softmac->network_list);
- INIT_LIST_HEAD(&softmac->events);
-
- mutex_init(&softmac->associnfo.mutex);
- INIT_DELAYED_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work);
- INIT_DELAYED_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout);
- softmac->start_scan = ieee80211softmac_start_scan_implementation;
- softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
- softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
-
- /* to start with, we can't send anything ... */
- netif_carrier_off(dev);
-
- return dev;
-}
-EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
-
-/* Clears the pending work queue items, stops all scans, etc. */
-void
-ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
-{
- unsigned long flags;
- struct ieee80211softmac_event *eventptr, *eventtmp;
- struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
- struct ieee80211softmac_network *netptr, *nettmp;
-
- ieee80211softmac_stop_scan(sm);
- ieee80211softmac_wait_for_scan(sm);
-
- spin_lock_irqsave(&sm->lock, flags);
- sm->running = 0;
-
- /* Free all pending assoc work items */
- cancel_delayed_work(&sm->associnfo.work);
-
- /* Free all pending scan work items */
- if(sm->scaninfo != NULL)
- cancel_delayed_work(&sm->scaninfo->softmac_scan);
-
- /* Free all pending auth work items */
- list_for_each_entry(authptr, &sm->auth_queue, list)
- cancel_delayed_work(&authptr->work);
-
- /* delete all pending event calls and work items */
- list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
- cancel_delayed_work(&eventptr->work);
-
- spin_unlock_irqrestore(&sm->lock, flags);
- flush_workqueue(sm->wq);
-
- /* now we should be save and no longer need locking... */
- spin_lock_irqsave(&sm->lock, flags);
- /* Free all pending auth work items */
- list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
- list_del(&authptr->list);
- kfree(authptr);
- }
-
- /* delete all pending event calls and work items */
- list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
- list_del(&eventptr->list);
- kfree(eventptr);
- }
-
- /* Free all networks */
- list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
- ieee80211softmac_del_network_locked(sm, netptr);
- if(netptr->challenge != NULL)
- kfree(netptr->challenge);
- kfree(netptr);
- }
-
- spin_unlock_irqrestore(&sm->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
-
-void free_ieee80211softmac(struct net_device *dev)
-{
- struct ieee80211softmac_device *sm = ieee80211_priv(dev);
- ieee80211softmac_clear_pending_work(sm);
- kfree(sm->scaninfo);
- kfree(sm->wpa.IE);
- destroy_workqueue(sm->wq);
- free_ieee80211(dev);
-}
-EXPORT_SYMBOL_GPL(free_ieee80211softmac);
-
-static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
-{
- struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
- /* I took out the sorting check, we're seperating by modulation now. */
- if (ri->count)
- return;
- /* otherwise assume we hav'em all! */
- if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
- ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
- ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
- ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
- ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
- }
- if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
- ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
- ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
- ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
- ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
- ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
- ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
- ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
- ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
- }
-}
-
-int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
-{
- int search;
- u8 search_rate;
-
- for (search = 0; search < ri->count; search++) {
- search_rate = ri->rates[search];
- search_rate &= ~IEEE80211_BASIC_RATE_MASK;
- if (rate == search_rate)
- return 1;
- }
-
- return 0;
-}
-
-u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_ratesinfo *ri, int basic_only)
-{
- u8 user_rate = mac->txrates.user_rate;
- int i;
-
- if (ri->count == 0)
- return IEEE80211_CCK_RATE_1MB;
-
- for (i = ri->count - 1; i >= 0; i--) {
- u8 rate = ri->rates[i];
- if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
- continue;
- rate &= ~IEEE80211_BASIC_RATE_MASK;
- if (rate > user_rate)
- continue;
- if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
- return rate;
- }
-
- /* If we haven't found a suitable rate by now, just trust the user */
- return user_rate;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
-
-void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
- u8 erp_value)
-{
- int use_protection;
- int short_preamble;
- u32 changes = 0;
-
- /* Barker preamble mode */
- short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
- && mac->associnfo.short_preamble_available) ? 1 : 0;
-
- /* Protection needed? */
- use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
-
- if (mac->bssinfo.short_preamble != short_preamble) {
- changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
- mac->bssinfo.short_preamble = short_preamble;
- }
-
- if (mac->bssinfo.use_protection != use_protection) {
- changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
- mac->bssinfo.use_protection = use_protection;
- }
-
- if (mac->bssinfo_change && changes)
- mac->bssinfo_change(mac->dev, changes);
-}
-
-void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
-{
- struct ieee80211softmac_txrates *txrates = &mac->txrates;
- u32 change = 0;
-
- change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
- txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
-
- change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
- txrates->default_fallback = lower_rate(mac, txrates->default_rate);
-
- change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
- txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
-
- if (mac->txrates_change)
- mac->txrates_change(mac->dev, change);
-
-}
-
-void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
-{
- struct ieee80211_device *ieee = mac->ieee;
- u32 change = 0;
- struct ieee80211softmac_txrates *txrates = &mac->txrates;
- struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
-
- /* TODO: We need some kind of state machine to lower the default rates
- * if we loose too many packets.
- */
- /* Change the default txrate to the highest possible value.
- * The txrate machine will lower it, if it is too high.
- */
- if (ieee->modulation & IEEE80211_OFDM_MODULATION)
- txrates->user_rate = IEEE80211_OFDM_RATE_24MB;
- else
- txrates->user_rate = IEEE80211_CCK_RATE_11MB;
-
- txrates->default_rate = IEEE80211_CCK_RATE_1MB;
- change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-
- txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
- change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
-
- txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
- change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
-
- txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
- change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
-
- if (mac->txrates_change)
- mac->txrates_change(mac->dev, change);
-
- change = 0;
-
- bssinfo->supported_rates.count = 0;
- memset(bssinfo->supported_rates.rates, 0,
- sizeof(bssinfo->supported_rates.rates));
- change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
-
- bssinfo->short_preamble = 0;
- change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
-
- bssinfo->use_protection = 0;
- change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
-
- if (mac->bssinfo_change)
- mac->bssinfo_change(mac->dev, change);
-
- mac->running = 1;
-}
-
-void ieee80211softmac_start(struct net_device *dev)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
- ieee80211softmac_start_check_rates(mac);
- ieee80211softmac_init_bss(mac);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_start);
-
-void ieee80211softmac_stop(struct net_device *dev)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
- ieee80211softmac_clear_pending_work(mac);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
-
-void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&mac->lock, flags);
- memcpy(mac->ratesinfo.rates, rates, count);
- mac->ratesinfo.count = count;
- spin_unlock_irqrestore(&mac->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
-
-static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
-{
- int i;
- struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
-
- for (i=0; i<ri->count-1; i++) {
- if (ri->rates[i] == rate)
- return ri->rates[i+1];
- }
- /* I guess we can't go any higher... */
- return ri->rates[ri->count];
-}
-
-u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
-{
- int i;
- struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
-
- for (i=delta; i<ri->count; i++) {
- if (ri->rates[i] == rate)
- return ri->rates[i-delta];
- }
- /* I guess we can't go any lower... */
- return ri->rates[0];
-}
-
-static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
- int amount)
-{
- u8 default_rate = mac->txrates.default_rate;
- u8 default_fallback = mac->txrates.default_fallback;
- u32 changes = 0;
-
- //TODO: This is highly experimental code.
- // Maybe the dynamic rate selection does not work
- // and it has to be removed again.
-
-printk("badness %d\n", mac->txrate_badness);
- mac->txrate_badness += amount;
- if (mac->txrate_badness <= -1000) {
- /* Very small badness. Try a faster bitrate. */
- default_rate = raise_rate(mac, default_rate);
- changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
- default_fallback = get_fallback_rate(mac, default_rate);
- changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
- mac->txrate_badness = 0;
-printk("Bitrate raised to %u\n", default_rate);
- } else if (mac->txrate_badness >= 10000) {
- /* Very high badness. Try a slower bitrate. */
- default_rate = lower_rate(mac, default_rate);
- changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
- default_fallback = get_fallback_rate(mac, default_rate);
- changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
- mac->txrate_badness = 0;
-printk("Bitrate lowered to %u\n", default_rate);
- }
-
- mac->txrates.default_rate = default_rate;
- mac->txrates.default_fallback = default_fallback;
-
- if (changes && mac->txrates_change)
- mac->txrates_change(mac->dev, changes);
-}
-
-void ieee80211softmac_fragment_lost(struct net_device *dev,
- u16 wl_seq)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&mac->lock, flags);
- ieee80211softmac_add_txrates_badness(mac, 1000);
- //TODO
-
- spin_unlock_irqrestore(&mac->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
-
-static int rate_cmp(const void *a_, const void *b_) {
- u8 *a, *b;
- a = (u8*)a_;
- b = (u8*)b_;
- return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
-}
-
-/* Allocate a softmac network struct and fill it from a network */
-struct ieee80211softmac_network *
-ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
- struct ieee80211_network *net)
-{
- struct ieee80211softmac_network *softnet;
- softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
- if(softnet == NULL)
- return NULL;
- memcpy(softnet->bssid, net->bssid, ETH_ALEN);
- softnet->channel = net->channel;
- softnet->essid.len = net->ssid_len;
- memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
-
- /* copy rates over */
- softnet->supported_rates.count = net->rates_len;
- memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
- memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
- softnet->supported_rates.count += net->rates_ex_len;
- sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
-
- /* we save the ERP value because it is needed at association time, and
- * many AP's do not include an ERP IE in the association response. */
- softnet->erp_value = net->erp_value;
-
- softnet->capabilities = net->capability;
- return softnet;
-}
-
-
-/* Add a network to the list, while locked */
-void
-ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *add_net)
-{
- struct ieee80211softmac_network *softmac_net;
-
- list_for_each_entry(softmac_net, &mac->network_list, list) {
- if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
- return;
- }
- list_add(&(add_net->list), &mac->network_list);
-}
-
-/* Add a network to the list, with locking */
-void
-ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *add_net)
-{
- unsigned long flags;
- spin_lock_irqsave(&mac->lock, flags);
- ieee80211softmac_add_network_locked(mac, add_net);
- spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-
-/* Delete a network from the list, while locked*/
-void
-ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *del_net)
-{
- list_del(&(del_net->list));
-}
-
-/* Delete a network from the list with locking */
-void
-ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *del_net)
-{
- unsigned long flags;
- spin_lock_irqsave(&mac->lock, flags);
- ieee80211softmac_del_network_locked(mac, del_net);
- spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-/* Get a network from the list by MAC while locked */
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
- u8 *bssid)
-{
- struct ieee80211softmac_network *softmac_net;
-
- list_for_each_entry(softmac_net, &mac->network_list, list) {
- if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
- return softmac_net;
- }
- return NULL;
-}
-
-/* Get a network from the list by BSSID with locking */
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
- u8 *bssid)
-{
- unsigned long flags;
- struct ieee80211softmac_network *softmac_net;
-
- spin_lock_irqsave(&mac->lock, flags);
- softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
- spin_unlock_irqrestore(&mac->lock, flags);
- return softmac_net;
-}
-
-/* Get a network from the list by ESSID while locked */
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_essid *essid)
-{
- struct ieee80211softmac_network *softmac_net;
-
- list_for_each_entry(softmac_net, &mac->network_list, list) {
- if (softmac_net->essid.len == essid->len &&
- !memcmp(softmac_net->essid.data, essid->data, essid->len))
- return softmac_net;
- }
- return NULL;
-}
-
-/* Get a network from the list by ESSID with locking */
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_essid *essid)
-{
- unsigned long flags;
- struct ieee80211softmac_network *softmac_net = NULL;
-
- spin_lock_irqsave(&mac->lock, flags);
- softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
- spin_unlock_irqrestore(&mac->lock, flags);
- return softmac_net;
-}
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Johannes Berg");
-MODULE_AUTHOR("Joseph Jezak");
-MODULE_AUTHOR("Larry Finger");
-MODULE_AUTHOR("Danny van Dyk");
-MODULE_AUTHOR("Michael Buesch");
-MODULE_DESCRIPTION("802.11 software MAC");
+++ /dev/null
-/*
- * Internal softmac API definitions.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#ifndef IEEE80211SOFTMAC_PRIV_H_
-#define IEEE80211SOFTMAC_PRIV_H_
-
-#include <net/ieee80211softmac.h>
-#include <net/ieee80211softmac_wx.h>
-#include <linux/kernel.h>
-#include <linux/stringify.h>
-
-
-#define PFX "SoftMAC: "
-
-#ifdef assert
-# undef assert
-#endif
-#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
-#define assert(expr) \
- do { \
- if (unlikely(!(expr))) { \
- printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \
- __FILE__, __LINE__, __FUNCTION__); \
- } \
- } while (0)
-#else
-#define assert(expr) do {} 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_IEEE80211_SOFTMAC_DEBUG
-# define dprintkl printkl
-#else
-# define dprintkl(f, x...) do { /* nothing */ } while (0)
-#endif
-
-/* debugging printk() */
-#ifdef dprintk
-# undef dprintk
-#endif
-#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
-# define dprintk(f, x...) do { printk(f ,##x); } while (0)
-#else
-# define dprintk(f, x...) do { /* nothing */ } while (0)
-#endif
-
-/* private definitions and prototypes */
-
-/*** prototypes from _scan.c */
-void ieee80211softmac_scan(struct work_struct *work);
-/* for internal use if scanning is needed */
-int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
-void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
-void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac);
-
-/* for use by _module.c to assign to the callbacks */
-int ieee80211softmac_start_scan_implementation(struct net_device *dev);
-void ieee80211softmac_stop_scan_implementation(struct net_device *dev);
-void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev);
-
-/*** Network prototypes from _module.c */
-struct ieee80211softmac_network * ieee80211softmac_create_network(
- struct ieee80211softmac_device *mac, struct ieee80211_network *net);
-void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *net);
-void ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *net);
-void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *net);
-void ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_network *net);
-struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked(
- struct ieee80211softmac_device *mac, u8 *ea);
-struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid(
- struct ieee80211softmac_device *mac, u8 *ea);
-struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked(
- struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
-struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid(
- struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_essid *essid);
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
- struct ieee80211softmac_essid *essid);
-
-/* Rates related */
-void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
- u8 erp_value);
-int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
-u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
-void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
-void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
-static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
- return ieee80211softmac_lower_rate_delta(mac, rate, 1);
-}
-
-static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
-{
- return ieee80211softmac_lower_rate_delta(mac, rate, 2);
-}
-
-
-/*** prototypes from _io.c */
-int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
- void* ptrarg, u32 type, u32 arg);
-int ieee80211softmac_handle_beacon(struct net_device *dev,
- struct ieee80211_beacon *beacon,
- struct ieee80211_network *network);
-
-/*** prototypes from _auth.c */
-/* do these have to go into the public header? */
-int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
-int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
-
-/* for use by _module.c to assign to the callbacks */
-int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
-int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth);
-
-/*** prototypes from _assoc.c */
-void ieee80211softmac_assoc_work(struct work_struct *work);
-int ieee80211softmac_handle_assoc_response(struct net_device * dev,
- struct ieee80211_assoc_response * resp,
- struct ieee80211_network * network);
-int ieee80211softmac_handle_disassoc(struct net_device * dev,
- struct ieee80211_disassoc * disassoc);
-int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
- struct ieee80211_reassoc_request * reassoc);
-void ieee80211softmac_assoc_timeout(struct work_struct *work);
-void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason);
-void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac);
-
-/* some helper functions */
-static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
-{
- return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
- (sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
- (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
-}
-
-static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
-{
- return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
- (sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
- (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
- ) || ieee80211softmac_scan_handlers_check_self(sm);
-}
-
-#define IEEE80211SOFTMAC_PROBE_DELAY HZ/50
-#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ)
-
-struct ieee80211softmac_network {
- struct list_head list; /* List */
- /* Network information copied from ieee80211_network */
- u8 bssid[ETH_ALEN];
- u8 channel;
- struct ieee80211softmac_essid essid;
-
- struct ieee80211softmac_ratesinfo supported_rates;
-
- /* SoftMAC specific */
- u16 authenticating:1, /* Status Flags */
- authenticated:1,
- auth_desynced_once:1;
-
- u8 erp_value; /* Saved ERP value */
- u16 capabilities; /* Capabilities bitfield */
- u8 challenge_len; /* Auth Challenge length */
- char *challenge; /* Challenge Text */
-};
-
-/* structure used to keep track of networks we're auth'ing to */
-struct ieee80211softmac_auth_queue_item {
- struct list_head list; /* List head */
- struct ieee80211softmac_network *net; /* Network to auth */
- struct ieee80211softmac_device *mac; /* SoftMAC device */
- u8 retry; /* Retry limit */
- u8 state; /* Auth State */
- struct delayed_work work; /* Work queue */
-};
-
-/* scanning information */
-struct ieee80211softmac_scaninfo {
- u8 current_channel_idx,
- number_channels;
- struct ieee80211_channel *channels;
- u8 started:1,
- stop:1;
- u8 skip_flags;
- struct completion finished;
- struct delayed_work softmac_scan;
- struct ieee80211softmac_device *mac;
-};
-
-/* private event struct */
-struct ieee80211softmac_event {
- struct list_head list;
- int event_type;
- void *event_context;
- struct delayed_work work;
- notify_function_ptr fun;
- void *context;
- struct ieee80211softmac_device *mac;
-};
-
-void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
-void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
-int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
- int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
-
-void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac);
-
-#endif /* IEEE80211SOFTMAC_PRIV_H_ */
+++ /dev/null
-/*
- * Scanning routines.
- *
- * These are not exported because they're assigned to the function pointers.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include <linux/completion.h>
-#include "ieee80211softmac_priv.h"
-
-/* internal, use to trigger scanning if needed.
- * Returns -EBUSY if already scanning,
- * result of start_scan otherwise */
-int
-ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&sm->lock, flags);
- if (sm->scanning)
- {
- spin_unlock_irqrestore(&sm->lock, flags);
- return -EINPROGRESS;
- }
- sm->scanning = 1;
- spin_unlock_irqrestore(&sm->lock, flags);
-
- ret = sm->start_scan(sm->dev);
- if (ret) {
- spin_lock_irqsave(&sm->lock, flags);
- sm->scanning = 0;
- spin_unlock_irqrestore(&sm->lock, flags);
- }
- return ret;
-}
-
-void
-ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sm->lock, flags);
-
- if (!sm->scanning) {
- spin_unlock_irqrestore(&sm->lock, flags);
- return;
- }
-
- spin_unlock_irqrestore(&sm->lock, flags);
- sm->stop_scan(sm->dev);
-}
-
-void
-ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sm->lock, flags);
-
- if (!sm->scanning) {
- spin_unlock_irqrestore(&sm->lock, flags);
- return;
- }
-
- spin_unlock_irqrestore(&sm->lock, flags);
- sm->wait_for_scan(sm->dev);
-}
-
-
-/* internal scanning implementation follows */
-void ieee80211softmac_scan(struct work_struct *work)
-{
- int invalid_channel;
- u8 current_channel_idx;
- struct ieee80211softmac_scaninfo *si =
- container_of(work, struct ieee80211softmac_scaninfo,
- softmac_scan.work);
- struct ieee80211softmac_device *sm = si->mac;
- unsigned long flags;
-
- while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
- current_channel_idx = si->current_channel_idx;
- si->current_channel_idx++; /* go to the next channel */
-
- invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
-
- if (!invalid_channel) {
- sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
- // FIXME make this user configurable (active/passive)
- if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
- printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
-
- /* also send directed management frame for the network we're looking for */
- // TODO: is this if correct, or should we do this only if scanning from assoc request?
- if (sm->associnfo.req_essid.len)
- ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
-
- spin_lock_irqsave(&sm->lock, flags);
- if (unlikely(!sm->running)) {
- /* Prevent reschedule on workqueue flush */
- spin_unlock_irqrestore(&sm->lock, flags);
- break;
- }
- queue_delayed_work(sm->wq, &si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
- spin_unlock_irqrestore(&sm->lock, flags);
- return;
- } else {
- dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
- }
- }
-
- spin_lock_irqsave(&sm->lock, flags);
- cancel_delayed_work(&si->softmac_scan);
- si->started = 0;
- spin_unlock_irqrestore(&sm->lock, flags);
-
- dprintk(PFX "Scanning finished: scanned %d channels starting with channel %d\n",
- sm->scaninfo->number_channels, sm->scaninfo->channels[0].channel);
- ieee80211softmac_scan_finished(sm);
- complete_all(&sm->scaninfo->finished);
-}
-
-static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
-{
- /* ugh. can we call this without having the spinlock held? */
- struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
- if (unlikely(!info))
- return NULL;
- INIT_DELAYED_WORK(&info->softmac_scan, ieee80211softmac_scan);
- info->mac = mac;
- init_completion(&info->finished);
- return info;
-}
-
-int ieee80211softmac_start_scan_implementation(struct net_device *dev)
-{
- struct ieee80211softmac_device *sm = ieee80211_priv(dev);
- unsigned long flags;
-
- if (!(dev->flags & IFF_UP))
- return -ENODEV;
-
- assert(ieee80211softmac_scan_handlers_check_self(sm));
- if (!ieee80211softmac_scan_handlers_check_self(sm))
- return -EINVAL;
-
- spin_lock_irqsave(&sm->lock, flags);
- /* it looks like we need to hold the lock here
- * to make sure we don't allocate two of these... */
- if (unlikely(!sm->scaninfo))
- sm->scaninfo = allocate_scaninfo(sm);
- if (unlikely(!sm->scaninfo)) {
- spin_unlock_irqrestore(&sm->lock, flags);
- return -ENOMEM;
- }
-
- sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
- if (0 /* not scanning in IEEE802.11b */)//TODO
- sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
- if (0 /* IEEE802.11a */) {//TODO
- sm->scaninfo->channels = sm->ieee->geo.a;
- sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
- } else {
- sm->scaninfo->channels = sm->ieee->geo.bg;
- sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
- }
- sm->scaninfo->current_channel_idx = 0;
- sm->scaninfo->started = 1;
- sm->scaninfo->stop = 0;
- INIT_COMPLETION(sm->scaninfo->finished);
- queue_delayed_work(sm->wq, &sm->scaninfo->softmac_scan, 0);
- spin_unlock_irqrestore(&sm->lock, flags);
- return 0;
-}
-
-void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
-{
- struct ieee80211softmac_device *sm = ieee80211_priv(dev);
- unsigned long flags;
-
- assert(ieee80211softmac_scan_handlers_check_self(sm));
- if (!ieee80211softmac_scan_handlers_check_self(sm))
- return;
-
- spin_lock_irqsave(&sm->lock, flags);
- assert(sm->scaninfo != NULL);
- if (sm->scaninfo) {
- if (sm->scaninfo->started)
- sm->scaninfo->stop = 1;
- else
- complete_all(&sm->scaninfo->finished);
- }
- spin_unlock_irqrestore(&sm->lock, flags);
-}
-
-void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
-{
- struct ieee80211softmac_device *sm = ieee80211_priv(dev);
- unsigned long flags;
-
- assert(ieee80211softmac_scan_handlers_check_self(sm));
- if (!ieee80211softmac_scan_handlers_check_self(sm))
- return;
-
- spin_lock_irqsave(&sm->lock, flags);
- if (!sm->scaninfo->started) {
- spin_unlock_irqrestore(&sm->lock, flags);
- return;
- }
- spin_unlock_irqrestore(&sm->lock, flags);
- wait_for_completion(&sm->scaninfo->finished);
-}
-
-/* this is what drivers (that do scanning) call when they're done */
-void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sm->lock, flags);
- sm->scanning = 0;
- spin_unlock_irqrestore(&sm->lock, flags);
-
- if (sm->associnfo.bssvalid) {
- struct ieee80211softmac_network *net;
-
- net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
- if (net)
- sm->set_channel(sm->dev, net->channel);
- }
- ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
+++ /dev/null
-/*
- * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- * Joseph Jezak <josejx@gentoo.org>
- * Larry Finger <Larry.Finger@lwfinger.net>
- * Danny van Dyk <kugelfang@gentoo.org>
- * Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-
-#include <net/iw_handler.h>
-/* for is_broadcast_ether_addr and is_zero_ether_addr */
-#include <linux/etherdevice.h>
-
-int
-ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra)
-{
- struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
- return ieee80211softmac_start_scan(sm);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
-
-
-/* if we're still scanning, return -EAGAIN so that userspace tools
- * can get the complete scan results, otherwise return 0. */
-int
-ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra)
-{
- unsigned long flags;
- struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
-
- spin_lock_irqsave(&sm->lock, flags);
- if (sm->scanning) {
- spin_unlock_irqrestore(&sm->lock, flags);
- return -EAGAIN;
- }
- spin_unlock_irqrestore(&sm->lock, flags);
- return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
-
-int
-ieee80211softmac_wx_set_essid(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra)
-{
- struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
- struct ieee80211softmac_auth_queue_item *authptr;
- int length = 0;
- DECLARE_MAC_BUF(mac);
-
-check_assoc_again:
- mutex_lock(&sm->associnfo.mutex);
- if((sm->associnfo.associating || sm->associnfo.associated) &&
- (data->essid.flags && data->essid.length)) {
- dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
- /* Cancel assoc work */
- cancel_delayed_work(&sm->associnfo.work);
- /* We don't have to do this, but it's a little cleaner */
- list_for_each_entry(authptr, &sm->auth_queue, list)
- cancel_delayed_work(&authptr->work);
- sm->associnfo.bssvalid = 0;
- sm->associnfo.bssfixed = 0;
- sm->associnfo.associating = 0;
- sm->associnfo.associated = 0;
- /* We must unlock to avoid deadlocks with the assoc workqueue
- * on the associnfo.mutex */
- mutex_unlock(&sm->associnfo.mutex);
- flush_workqueue(sm->wq);
- /* Avoid race! Check assoc status again. Maybe someone started an
- * association while we flushed. */
- goto check_assoc_again;
- }
-
- sm->associnfo.static_essid = 0;
- sm->associnfo.assoc_wait = 0;
-
- if (data->essid.flags && data->essid.length) {
- length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
- if (length) {
- memcpy(sm->associnfo.req_essid.data, extra, length);
- sm->associnfo.static_essid = 1;
- }
- }
-
- /* set our requested ESSID length.
- * If applicable, we have already copied the data in */
- sm->associnfo.req_essid.len = length;
-
- sm->associnfo.associating = 1;
- /* queue lower level code to do work (if necessary) */
- queue_delayed_work(sm->wq, &sm->associnfo.work, 0);
-
- mutex_unlock(&sm->associnfo.mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
-
-int
-ieee80211softmac_wx_get_essid(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra)
-{
- struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
-
- mutex_lock(&sm->associnfo.mutex);
- /* If all fails, return ANY (empty) */
- data->essid.length = 0;
- data->essid.flags = 0; /* active */
-
- /* If we have a statically configured ESSID then return it */
- if (sm->associnfo.static_essid) {
- data->essid.length = sm->associnfo.req_essid.len;
- data->essid.flags = 1; /* active */
- memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
- dprintk(KERN_INFO PFX "Getting essid from req_essid\n");
- } else if (sm->associnfo.associated || sm->associnfo.associating) {
- /* If we're associating/associated, return that */
- data->essid.length = sm->associnfo.associate_essid.len;
- data->essid.flags = 1; /* active */
- memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
- dprintk(KERN_INFO PFX "Getting essid from associate_essid\n");
- }
- mutex_unlock(&sm->associnfo.mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
-
-int
-ieee80211softmac_wx_set_rate(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
- struct ieee80211_device *ieee = mac->ieee;
- unsigned long flags;
- s32 in_rate = data->bitrate.value;
- u8 rate;
- int is_ofdm = 0;
- int err = -EINVAL;
-
- if (in_rate == -1) {
- if (ieee->modulation & IEEE80211_OFDM_MODULATION)
- in_rate = 24000000;
- else
- in_rate = 11000000;
- }
-
- switch (in_rate) {
- case 1000000:
- rate = IEEE80211_CCK_RATE_1MB;
- break;
- case 2000000:
- rate = IEEE80211_CCK_RATE_2MB;
- break;
- case 5500000:
- rate = IEEE80211_CCK_RATE_5MB;
- break;
- case 11000000:
- rate = IEEE80211_CCK_RATE_11MB;
- break;
- case 6000000:
- rate = IEEE80211_OFDM_RATE_6MB;
- is_ofdm = 1;
- break;
- case 9000000:
- rate = IEEE80211_OFDM_RATE_9MB;
- is_ofdm = 1;
- break;
- case 12000000:
- rate = IEEE80211_OFDM_RATE_12MB;
- is_ofdm = 1;
- break;
- case 18000000:
- rate = IEEE80211_OFDM_RATE_18MB;
- is_ofdm = 1;
- break;
- case 24000000:
- rate = IEEE80211_OFDM_RATE_24MB;
- is_ofdm = 1;
- break;
- case 36000000:
- rate = IEEE80211_OFDM_RATE_36MB;
- is_ofdm = 1;
- break;
- case 48000000:
- rate = IEEE80211_OFDM_RATE_48MB;
- is_ofdm = 1;
- break;
- case 54000000:
- rate = IEEE80211_OFDM_RATE_54MB;
- is_ofdm = 1;
- break;
- default:
- goto out;
- }
-
- spin_lock_irqsave(&mac->lock, flags);
-
- /* Check if correct modulation for this PHY. */
- if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
- goto out_unlock;
-
- mac->txrates.user_rate = rate;
- ieee80211softmac_recalc_txrates(mac);
- err = 0;
-
-out_unlock:
- spin_unlock_irqrestore(&mac->lock, flags);
-out:
- return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
-
-int
-ieee80211softmac_wx_get_rate(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
- unsigned long flags;
- int err = -EINVAL;
-
- spin_lock_irqsave(&mac->lock, flags);
-
- if (unlikely(!mac->running)) {
- err = -ENODEV;
- goto out_unlock;
- }
-
- switch (mac->txrates.default_rate) {
- case IEEE80211_CCK_RATE_1MB:
- data->bitrate.value = 1000000;
- break;
- case IEEE80211_CCK_RATE_2MB:
- data->bitrate.value = 2000000;
- break;
- case IEEE80211_CCK_RATE_5MB:
- data->bitrate.value = 5500000;
- break;
- case IEEE80211_CCK_RATE_11MB:
- data->bitrate.value = 11000000;
- break;
- case IEEE80211_OFDM_RATE_6MB:
- data->bitrate.value = 6000000;
- break;
- case IEEE80211_OFDM_RATE_9MB:
- data->bitrate.value = 9000000;
- break;
- case IEEE80211_OFDM_RATE_12MB:
- data->bitrate.value = 12000000;
- break;
- case IEEE80211_OFDM_RATE_18MB:
- data->bitrate.value = 18000000;
- break;
- case IEEE80211_OFDM_RATE_24MB:
- data->bitrate.value = 24000000;
- break;
- case IEEE80211_OFDM_RATE_36MB:
- data->bitrate.value = 36000000;
- break;
- case IEEE80211_OFDM_RATE_48MB:
- data->bitrate.value = 48000000;
- break;
- case IEEE80211_OFDM_RATE_54MB:
- data->bitrate.value = 54000000;
- break;
- default:
- assert(0);
- goto out_unlock;
- }
- err = 0;
-out_unlock:
- spin_unlock_irqrestore(&mac->lock, flags);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
-
-int
-ieee80211softmac_wx_get_wap(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
- int err = 0;
-
- mutex_lock(&mac->associnfo.mutex);
- if (mac->associnfo.bssvalid)
- memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
- else
- memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
- data->ap_addr.sa_family = ARPHRD_ETHER;
- mutex_unlock(&mac->associnfo.mutex);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
-
-int
-ieee80211softmac_wx_set_wap(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data,
- char *extra)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
-
- /* sanity check */
- if (data->ap_addr.sa_family != ARPHRD_ETHER) {
- return -EINVAL;
- }
-
- mutex_lock(&mac->associnfo.mutex);
- if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
- /* the bssid we have is not to be fixed any longer,
- * and we should reassociate to the best AP. */
- mac->associnfo.bssfixed = 0;
- /* force reassociation */
- mac->associnfo.bssvalid = 0;
- if (mac->associnfo.associated)
- queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
- } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
- /* the bssid we have is no longer fixed */
- mac->associnfo.bssfixed = 0;
- } else {
- if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
- if (mac->associnfo.associating || mac->associnfo.associated) {
- /* bssid unchanged and associated or associating - just return */
- goto out;
- }
- } else {
- /* copy new value in data->ap_addr.sa_data to bssid */
- memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
- }
- /* tell the other code that this bssid should be used no matter what */
- mac->associnfo.bssfixed = 1;
- /* queue associate if new bssid or (old one again and not associated) */
- queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
- }
-
- out:
- mutex_unlock(&mac->associnfo.mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
-
-int
-ieee80211softmac_wx_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- unsigned long flags;
- int err = 0;
- char *buf;
- int i;
-
- mutex_lock(&mac->associnfo.mutex);
- spin_lock_irqsave(&mac->lock, flags);
- /* bleh. shouldn't be locked for that kmalloc... */
-
- if (wrqu->data.length) {
- if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
- /* this is an IE, so the length must be
- * correct. Is it possible though that
- * more than one IE is passed in?
- */
- err = -EINVAL;
- goto out;
- }
- if (mac->wpa.IEbuflen <= wrqu->data.length) {
- buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
- if (!buf) {
- err = -ENOMEM;
- goto out;
- }
- kfree(mac->wpa.IE);
- mac->wpa.IE = buf;
- mac->wpa.IEbuflen = wrqu->data.length;
- }
- memcpy(mac->wpa.IE, extra, wrqu->data.length);
- dprintk(KERN_INFO PFX "generic IE set to ");
- for (i=0;i<wrqu->data.length;i++)
- dprintk("%.2x", (u8)mac->wpa.IE[i]);
- dprintk("\n");
- mac->wpa.IElen = wrqu->data.length;
- } else {
- kfree(mac->wpa.IE);
- mac->wpa.IE = NULL;
- mac->wpa.IElen = 0;
- mac->wpa.IEbuflen = 0;
- }
-
- out:
- spin_unlock_irqrestore(&mac->lock, flags);
- mutex_unlock(&mac->associnfo.mutex);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
-
-int
-ieee80211softmac_wx_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- unsigned long flags;
- int err = 0;
- int space = wrqu->data.length;
-
- mutex_lock(&mac->associnfo.mutex);
- spin_lock_irqsave(&mac->lock, flags);
-
- wrqu->data.length = 0;
-
- if (mac->wpa.IE && mac->wpa.IElen) {
- wrqu->data.length = mac->wpa.IElen;
- if (mac->wpa.IElen <= space)
- memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
- else
- err = -E2BIG;
- }
- spin_unlock_irqrestore(&mac->lock, flags);
- mutex_unlock(&mac->associnfo.mutex);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
-
-int
-ieee80211softmac_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
- u16 reason = mlme->reason_code;
- struct ieee80211softmac_network *net;
- int err = -EINVAL;
-
- mutex_lock(&mac->associnfo.mutex);
-
- if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
- printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
- goto out;
- }
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
- if (!net) {
- printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
- goto out;
- }
- err = ieee80211softmac_deauth_req(mac, net, reason);
- goto out;
- case IW_MLME_DISASSOC:
- ieee80211softmac_send_disassoc_req(mac, reason);
- mac->associnfo.associated = 0;
- mac->associnfo.associating = 0;
- err = 0;
- goto out;
- default:
- err = -EOPNOTSUPP;
- }
-
-out:
- mutex_unlock(&mac->associnfo.mutex);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);
{
struct sock *sk = sock->sk;
int err = 0;
+ struct net *net = sk->sk_net;
switch (cmd) {
case SIOCGSTAMP:
case SIOCADDRT:
case SIOCDELRT:
case SIOCRTMSG:
- err = ip_rt_ioctl(sk->sk_net, cmd, (void __user *)arg);
+ err = ip_rt_ioctl(net, cmd, (void __user *)arg);
break;
case SIOCDARP:
case SIOCGARP:
case SIOCSARP:
- err = arp_ioctl(sk->sk_net, cmd, (void __user *)arg);
+ err = arp_ioctl(net, cmd, (void __user *)arg);
break;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCSIFPFLAGS:
case SIOCGIFPFLAGS:
case SIOCSIFFLAGS:
- err = devinet_ioctl(cmd, (void __user *)arg);
+ err = devinet_ioctl(net, cmd, (void __user *)arg);
break;
default:
if (sk->sk_prot->ioctl)
if (sysctl_ip_dynaddr > 1) {
printk(KERN_INFO "%s(): shifting inet->"
"saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
- __FUNCTION__,
+ __func__,
NIPQUAD(old_saddr),
NIPQUAD(new_saddr));
}
ip_init();
- tcp_v4_init(&inet_family_ops);
+ tcp_v4_init();
/* Setup TCP slab cache for open requests. */
tcp_init();
* Set the ICMP layer up
*/
- icmp_init(&inet_family_ops);
+ if (icmp_init() < 0)
+ panic("Failed to create the ICMP control socket.\n");
/*
* Initialise the multicast router
return 1;
}
- paddr = ((struct rtable*)skb->dst)->rt_gateway;
+ paddr = skb->rtable->rt_gateway;
if (arp_set_predefined(inet_addr_type(&init_net, paddr), haddr, paddr, dev))
return 0;
* Allocate a buffer
*/
- skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
- + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
+ skb = alloc_skb(arp_hdr_len(dev) + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
if (skb == NULL)
return NULL;
skb_reserve(skb, LL_RESERVED_SPACE(dev));
skb_reset_network_header(skb);
- arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
+ arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev));
skb->dev = dev;
skb->protocol = htons(ETH_P_ARP);
if (src_hw == NULL)
if (arp->ar_op == htons(ARPOP_REQUEST) &&
ip_route_input(skb, tip, sip, 0, dev) == 0) {
- rt = (struct rtable*)skb->dst;
+ rt = skb->rtable;
addr_type = rt->rt_type;
if (addr_type == RTN_LOCAL) {
goto freeskb;
/* ARP header, plus 2 device addresses, plus 2 IP addresses. */
- if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
- (2 * dev->addr_len) +
- (2 * sizeof(u32)))))
+ if (!pskb_may_pull(skb, arp_hdr_len(dev)))
goto freeskb;
arp = arp_hdr(skb);
ASSERT_RTNL();
- if (net != &init_net)
- return -EINVAL;
-
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
if (err < 0)
goto errout;
ASSERT_RTNL();
- if (net != &init_net)
- return -EINVAL;
-
ifa = rtm_to_ifaddr(net, nlh);
if (IS_ERR(ifa))
return PTR_ERR(ifa);
}
-int devinet_ioctl(unsigned int cmd, void __user *arg)
+int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct ifreq ifr;
struct sockaddr_in sin_orig;
*colon = 0;
#ifdef CONFIG_KMOD
- dev_load(&init_net, ifr.ifr_name);
+ dev_load(net, ifr.ifr_name);
#endif
switch (cmd) {
rtnl_lock();
ret = -ENODEV;
- if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL)
+ if ((dev = __dev_get_by_name(net, ifr.ifr_name)) == NULL)
goto done;
if (colon)
{
__be32 addr = 0;
struct in_device *in_dev;
+ struct net *net = dev->nd_net;
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
*/
read_lock(&dev_base_lock);
rcu_read_lock();
- for_each_netdev(&init_net, dev) {
+ for_each_netdev(net, dev) {
if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
continue;
struct net_device *dev = ptr;
struct in_device *in_dev = __in_dev_get_rtnl(dev);
- if (dev->nd_net != &init_net)
- return NOTIFY_DONE;
-
ASSERT_RTNL();
if (!in_dev) {
struct in_ifaddr *ifa;
int s_ip_idx, s_idx = cb->args[0];
- if (net != &init_net)
- return 0;
-
s_ip_idx = ip_idx = cb->args[1];
idx = 0;
for_each_netdev(net, dev) {
*
* On SMP we have one ICMP socket per-cpu.
*/
-static DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL;
-#define icmp_socket __get_cpu_var(__icmp_socket)
+static struct sock *icmp_sk(struct net *net)
+{
+ return net->ipv4.icmp_sk[smp_processor_id()];
+}
-static inline int icmp_xmit_lock(void)
+static inline int icmp_xmit_lock(struct sock *sk)
{
local_bh_disable();
- if (unlikely(!spin_trylock(&icmp_socket->sk->sk_lock.slock))) {
+ if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
/* This can happen if the output path signals a
* dst_link_failure() for an outgoing ICMP packet.
*/
return 0;
}
-static inline void icmp_xmit_unlock(void)
+static inline void icmp_xmit_unlock(struct sock *sk)
{
- spin_unlock_bh(&icmp_socket->sk->sk_lock.slock);
+ spin_unlock_bh(&sk->sk_lock.slock);
}
/*
static void icmp_push_reply(struct icmp_bxm *icmp_param,
struct ipcm_cookie *ipc, struct rtable *rt)
{
+ struct sock *sk;
struct sk_buff *skb;
- if (ip_append_data(icmp_socket->sk, icmp_glue_bits, icmp_param,
+ sk = icmp_sk(rt->u.dst.dev->nd_net);
+ if (ip_append_data(sk, icmp_glue_bits, icmp_param,
icmp_param->data_len+icmp_param->head_len,
icmp_param->head_len,
ipc, rt, MSG_DONTWAIT) < 0)
- ip_flush_pending_frames(icmp_socket->sk);
- else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) {
+ ip_flush_pending_frames(sk);
+ else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
struct icmphdr *icmph = icmp_hdr(skb);
__wsum csum = 0;
struct sk_buff *skb1;
- skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) {
+ skb_queue_walk(&sk->sk_write_queue, skb1) {
csum = csum_add(csum, skb1->csum);
}
csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
icmp_param->head_len, csum);
icmph->checksum = csum_fold(csum);
skb->ip_summed = CHECKSUM_NONE;
- ip_push_pending_frames(icmp_socket->sk);
+ ip_push_pending_frames(sk);
}
}
static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
{
- struct sock *sk = icmp_socket->sk;
- struct inet_sock *inet = inet_sk(sk);
struct ipcm_cookie ipc;
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
+ struct net *net = rt->u.dst.dev->nd_net;
+ struct sock *sk = icmp_sk(net);
+ struct inet_sock *inet = inet_sk(sk);
__be32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb))
return;
- if (icmp_xmit_lock())
+ if (icmp_xmit_lock(sk))
return;
icmp_param->data.icmph.checksum = 0;
.tos = RT_TOS(ip_hdr(skb)->tos) } },
.proto = IPPROTO_ICMP };
security_skb_classify_flow(skb, &fl);
- if (ip_route_output_key(rt->u.dst.dev->nd_net, &rt, &fl))
+ if (ip_route_output_key(net, &rt, &fl))
goto out_unlock;
}
if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
icmp_push_reply(icmp_param, &ipc, rt);
ip_rt_put(rt);
out_unlock:
- icmp_xmit_unlock();
+ icmp_xmit_unlock(sk);
}
struct iphdr *iph;
int room;
struct icmp_bxm icmp_param;
- struct rtable *rt = (struct rtable *)skb_in->dst;
+ struct rtable *rt = skb_in->rtable;
struct ipcm_cookie ipc;
__be32 saddr;
u8 tos;
struct net *net;
+ struct sock *sk;
if (!rt)
goto out;
net = rt->u.dst.dev->nd_net;
+ sk = icmp_sk(net);
/*
* Find the original header. It is expected to be valid, of course.
}
}
- if (icmp_xmit_lock())
+ if (icmp_xmit_lock(sk))
return;
/*
icmp_param.data.icmph.checksum = 0;
icmp_param.skb = skb_in;
icmp_param.offset = skb_network_offset(skb_in);
- inet_sk(icmp_socket->sk)->tos = tos;
+ inet_sk(sk)->tos = tos;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
RT_TOS(tos), rt2->u.dst.dev);
dst_release(&rt2->u.dst);
- rt2 = (struct rtable *)skb_in->dst;
+ rt2 = skb_in->rtable;
skb_in->dst = odst;
}
ende:
ip_rt_put(rt);
out_unlock:
- icmp_xmit_unlock();
+ icmp_xmit_unlock(sk);
out:;
}
static void icmp_address_reply(struct sk_buff *skb)
{
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
struct net_device *dev = skb->dev;
struct in_device *in_dev;
struct in_ifaddr *ifa;
int icmp_rcv(struct sk_buff *skb)
{
struct icmphdr *icmph;
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
int nh;
},
};
-void __init icmp_init(struct net_proto_family *ops)
+static void __net_exit icmp_sk_exit(struct net *net)
{
- struct inet_sock *inet;
int i;
- for_each_possible_cpu(i) {
- int err;
+ for_each_possible_cpu(i)
+ sk_release_kernel(net->ipv4.icmp_sk[i]);
+ kfree(net->ipv4.icmp_sk);
+ net->ipv4.icmp_sk = NULL;
+}
- err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP,
- &per_cpu(__icmp_socket, i));
+int __net_init icmp_sk_init(struct net *net)
+{
+ int i, err;
+ net->ipv4.icmp_sk =
+ kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
+ if (net->ipv4.icmp_sk == NULL)
+ return -ENOMEM;
+
+ for_each_possible_cpu(i) {
+ struct sock *sk;
+ struct socket *sock;
+ struct inet_sock *inet;
+
+ err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, &sock);
if (err < 0)
- panic("Failed to create the ICMP control socket.\n");
+ goto fail;
+
+ net->ipv4.icmp_sk[i] = sk = sock->sk;
+ sk_change_net(sk, net);
- per_cpu(__icmp_socket, i)->sk->sk_allocation = GFP_ATOMIC;
+ sk->sk_allocation = GFP_ATOMIC;
/* Enough space for 2 64K ICMP packets, including
* sk_buff struct overhead.
*/
- per_cpu(__icmp_socket, i)->sk->sk_sndbuf =
+ sk->sk_sndbuf =
(2 * ((64 * 1024) + sizeof(struct sk_buff)));
- inet = inet_sk(per_cpu(__icmp_socket, i)->sk);
+ inet = inet_sk(sk);
inet->uc_ttl = -1;
inet->pmtudisc = IP_PMTUDISC_DONT;
* see it, we do not wish this socket to see incoming
* packets.
*/
- per_cpu(__icmp_socket, i)->sk->sk_prot->unhash(per_cpu(__icmp_socket, i)->sk);
+ sk->sk_prot->unhash(sk);
}
+ return 0;
+
+fail:
+ for_each_possible_cpu(i)
+ sk_release_kernel(net->ipv4.icmp_sk[i]);
+ kfree(net->ipv4.icmp_sk);
+ return err;
+}
+
+static struct pernet_operations __net_initdata icmp_sk_ops = {
+ .init = icmp_sk_init,
+ .exit = icmp_sk_exit,
+};
+
+int __init icmp_init(void)
+{
+ return register_pernet_device(&icmp_sk_ops);
}
EXPORT_SYMBOL(icmp_err_convert);
case IGMPV2_HOST_MEMBERSHIP_REPORT:
case IGMPV3_HOST_MEMBERSHIP_REPORT:
/* Is it our report looped back? */
- if (((struct rtable*)skb->dst)->fl.iif == 0)
+ if (skb->rtable->fl.iif == 0)
break;
/* don't rely on MC router hearing unicast reports */
if (skb->pkt_type == PACKET_MULTICAST ||
ASSERT_RTNL();
+ if (in_dev->dev->nd_net != &init_net)
+ return;
+
for (im=in_dev->mc_list; im; im=im->next) {
if (im->multiaddr == addr) {
im->users++;
ASSERT_RTNL();
+ if (in_dev->dev->nd_net != &init_net)
+ return;
+
for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
if (i->multiaddr==addr) {
if (--i->users == 0) {
ASSERT_RTNL();
+ if (in_dev->dev->nd_net != &init_net)
+ return;
+
for (i=in_dev->mc_list; i; i=i->next)
igmp_group_dropped(i);
{
ASSERT_RTNL();
+ if (in_dev->dev->nd_net != &init_net)
+ return;
+
in_dev->mc_tomb = NULL;
#ifdef CONFIG_IP_MULTICAST
in_dev->mr_gq_running = 0;
ASSERT_RTNL();
+ if (in_dev->dev->nd_net != &init_net)
+ return;
+
ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
for (i=in_dev->mc_list; i; i=i->next)
ASSERT_RTNL();
+ if (in_dev->dev->nd_net != &init_net)
+ return;
+
/* Deactivate timers */
ip_mc_down(in_dev);
if (!ipv4_is_multicast(addr))
return -EINVAL;
+ if (sk->sk_net != &init_net)
+ return -EPROTONOSUPPORT;
+
rtnl_lock();
in_dev = ip_mc_find_dev(imr);
u32 ifindex;
int ret = -EADDRNOTAVAIL;
+ if (sk->sk_net != &init_net)
+ return -EPROTONOSUPPORT;
+
rtnl_lock();
in_dev = ip_mc_find_dev(imr);
ifindex = imr->imr_ifindex;
if (!ipv4_is_multicast(addr))
return -EINVAL;
+ if (sk->sk_net != &init_net)
+ return -EPROTONOSUPPORT;
+
rtnl_lock();
imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr;
msf->imsf_fmode != MCAST_EXCLUDE)
return -EINVAL;
+ if (sk->sk_net != &init_net)
+ return -EPROTONOSUPPORT;
+
rtnl_lock();
imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
if (!ipv4_is_multicast(addr))
return -EINVAL;
+ if (sk->sk_net != &init_net)
+ return -EPROTONOSUPPORT;
+
rtnl_lock();
imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
if (!ipv4_is_multicast(addr))
return -EINVAL;
+ if (sk->sk_net != &init_net)
+ return -EPROTONOSUPPORT;
+
rtnl_lock();
err = -EADDRNOTAVAIL;
if (inet->mc_list == NULL)
return;
+ if (sk->sk_net != &init_net)
+ return;
+
rtnl_lock();
while ((iml = inet->mc_list) != NULL) {
struct in_device *in_dev;
if (time_after_eq(now, req->expires)) {
if ((req->retrans < thresh ||
(inet_rsk(req)->acked && req->retrans < max_retries))
- && !req->rsk_ops->rtx_syn_ack(parent, req, NULL)) {
+ && !req->rsk_ops->rtx_syn_ack(parent, req)) {
unsigned long timeo;
if (req->retrans++ == 0)
if (!xfrm4_route_forward(skb))
goto drop;
- rt = (struct rtable*)skb->dst;
+ rt = skb->rtable;
if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
goto sr_failed;
#ifdef CONFIG_NET_IPGRE_BROADCAST
if (ipv4_is_multicast(iph->daddr)) {
/* Looped back packet, drop it! */
- if (((struct rtable*)skb->dst)->fl.iif == 0)
+ if (skb->rtable->fl.iif == 0)
goto drop;
tunnel->stat.multicast++;
skb->pkt_type = PACKET_BROADCAST;
}
if (skb->protocol == htons(ETH_P_IP)) {
- rt = (struct rtable*)skb->dst;
+ rt = skb->rtable;
if ((dst = rt->rt_gateway) == 0)
goto tx_error_icmp;
}
if (iph->ihl > 5 && ip_rcv_options(skb))
goto drop;
- rt = (struct rtable*)skb->dst;
+ rt = skb->rtable;
if (rt->rt_type == RTN_MULTICAST)
IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);
else if (rt->rt_type == RTN_BROADCAST)
sptr = skb_network_header(skb);
dptr = dopt->__data;
- if (skb->dst)
- daddr = ((struct rtable*)skb->dst)->rt_spec_dst;
- else
- daddr = ip_hdr(skb)->daddr;
+ daddr = skb->rtable->rt_spec_dst;
if (sopt->rr) {
optlen = sptr[sopt->rr+1];
unsigned char * optptr;
int optlen;
unsigned char * pp_ptr = NULL;
- struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL;
+ struct rtable *rt = skb ? skb->rtable : NULL;
if (!opt) {
opt = &(IPCB(skb)->opt);
{
struct ip_options * opt = &(IPCB(skb)->opt);
unsigned char * optptr;
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
unsigned char *raw = skb_network_header(skb);
if (opt->rr_needaddr) {
__be32 nexthop;
struct iphdr *iph = ip_hdr(skb);
unsigned char *optptr = skb_network_header(skb) + opt->srr;
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
struct rtable *rt2;
int err;
}
memcpy(&nexthop, &optptr[srrptr-1], 4);
- rt = (struct rtable*)skb->dst;
- skb->dst = NULL;
+ rt = skb->rtable;
+ skb->rtable = NULL;
err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);
- rt2 = (struct rtable*)skb->dst;
+ rt2 = skb->rtable;
if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
ip_rt_put(rt2);
- skb->dst = &rt->u.dst;
+ skb->rtable = rt;
return -EINVAL;
}
ip_rt_put(rt);
__be32 saddr, __be32 daddr, struct ip_options *opt)
{
struct inet_sock *inet = inet_sk(sk);
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
struct iphdr *iph;
/* Build the IP header. */
int ip_mc_output(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
struct net_device *dev = rt->u.dst.dev;
/*
/* Skip all of this if the packet is already routed,
* f.e. by something like SCTP.
*/
- rt = (struct rtable *) skb->dst;
+ rt = skb->rtable;
if (rt != NULL)
goto packet_routed;
unsigned int mtu, hlen, left, len, ll_rs, pad;
int offset;
__be16 not_last_frag;
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
int err = 0;
dev = rt->u.dst.dev;
} replyopts;
struct ipcm_cookie ipc;
__be32 daddr;
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
if (ip_options_echo(&replyopts.opt, skb))
return;
static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
{
struct in_pktinfo info;
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
if (rt) {
mm_segment_t oldfs = get_fs();
set_fs(get_ds());
- res = devinet_ioctl(cmd, (struct ifreq __user *) arg);
+ res = devinet_ioctl(&init_net, cmd, (struct ifreq __user *) arg);
set_fs(oldfs);
return res;
}
if (rarp->ar_pro != htons(ETH_P_IP))
goto drop;
- if (!pskb_may_pull(skb,
- sizeof(struct arphdr) +
- (2 * dev->addr_len) +
- (2 * 4)))
+ if (!pskb_may_pull(skb, arp_hdr_len(dev)))
goto drop;
/* OK, it is all there and looks valid, process... */
if (!dst) {
/* NBMA tunnel */
- if ((rt = (struct rtable*)skb->dst) == NULL) {
+ if ((rt = skb->rtable) == NULL) {
tunnel->stat.tx_fifo_errors++;
goto tx_error;
}
if (vif_table[vif].dev != skb->dev) {
int true_vifi;
- if (((struct rtable*)skb->dst)->fl.iif == 0) {
+ if (skb->rtable->fl.iif == 0) {
/* It is our own packet, looped back.
Very complicated situation...
int ip_mr_input(struct sk_buff *skb)
{
struct mfc_cache *cache;
- int local = ((struct rtable*)skb->dst)->rt_flags&RTCF_LOCAL;
+ int local = skb->rtable->rt_flags&RTCF_LOCAL;
/* Packet is looped back after forward, it should not be
forwarded second time, but still can be delivered locally.
{
int err;
struct mfc_cache *cache;
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
read_lock(&mrt_lock);
cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);
IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
"%u.%u.%u.%u:%u to app %s on port %u\n",
- __FUNCTION__,
+ __func__,
NIPQUAD(cp->caddr), ntohs(cp->cport),
NIPQUAD(cp->vaddr), ntohs(cp->vport),
inc->name, ntohs(inc->port));
IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
"%u.%u.%u.%u:%u to app %s on port %u\n",
- __FUNCTION__,
+ __func__,
NIPQUAD(cp->caddr), ntohs(cp->cport),
NIPQUAD(cp->vaddr), ntohs(cp->vport),
inc->name, ntohs(inc->port));
if (!tinfo)
return -ENOMEM;
- IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, task_pid_nr(current));
+ IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current));
IP_VS_DBG(7, "Each ip_vs_sync_conn entry need %Zd bytes\n",
sizeof(struct ip_vs_sync_conn));
(state == IP_VS_STATE_BACKUP && !sync_backup_pid))
return -ESRCH;
- IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, task_pid_nr(current));
+ IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current));
IP_VS_INFO("stopping sync thread %d ...\n",
(state == IP_VS_STATE_MASTER) ?
sync_master_pid : sync_backup_pid);
do { \
if (!(x)) \
printk("ARP_NF_ASSERT: %s:%s:%u\n", \
- __FUNCTION__, __FILE__, __LINE__); \
+ __func__, __FILE__, __LINE__); \
} while(0)
#else
#define ARP_NF_ASSERT(x)
void *table_base;
struct xt_table_info *private;
- /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
- if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
- (2 * skb->dev->addr_len) +
- (2 * sizeof(u32)))))
+ if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
return NF_DROP;
indev = in ? in->name : nulldevname;
do { \
if (!(x)) \
printk("IP_NF_ASSERT: %s:%s:%u\n", \
- __FUNCTION__, __FILE__, __LINE__); \
+ __func__, __FILE__, __LINE__); \
} while(0)
#else
#define IP_NF_ASSERT(x)
return NF_ACCEPT;
mr = targinfo;
- rt = (struct rtable *)skb->dst;
+ rt = skb->rtable;
newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
if (!newsrc) {
printk("MASQUERADE: %s ate my IP address\n", out->name);
unsigned long event,
void *ptr)
{
- const struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
-
- if (event == NETDEV_DOWN) {
- /* IP address was deleted. Search entire table for
- conntracks which were associated with that device,
- and forget them. */
- NF_CT_ASSERT(dev->ifindex != 0);
-
- nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
- }
-
- return NOTIFY_DONE;
+ struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
+ return masq_device_event(this, event, dev);
}
static struct notifier_block masq_dev_notifier = {
.open = ct_cpu_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release,
};
int __init nf_conntrack_ipv4_compat_init(void)
const char *rep_buffer,
unsigned int rep_len)
{
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
struct iphdr *iph;
struct tcphdr *tcph;
int oldlen, datalen;
const char *rep_buffer,
unsigned int rep_len)
{
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
struct iphdr *iph;
struct udphdr *udph;
int datalen, oldlen;
#ifdef CONFIG_PROC_FS
struct rt_cache_iter_state {
+ struct seq_net_private p;
int bucket;
int genid;
};
rcu_read_lock_bh();
r = rcu_dereference(rt_hash_table[st->bucket].chain);
while (r) {
- if (r->rt_genid == st->genid)
+ if (r->u.dst.dev->nd_net == st->p.net &&
+ r->rt_genid == st->genid)
return r;
r = rcu_dereference(r->u.dst.rt_next);
}
return r;
}
-static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct rtable *r)
+static struct rtable *__rt_cache_get_next(struct rt_cache_iter_state *st,
+ struct rtable *r)
{
r = r->u.dst.rt_next;
while (!r) {
return rcu_dereference(r);
}
+static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st,
+ struct rtable *r)
+{
+ while ((r = __rt_cache_get_next(st, r)) != NULL) {
+ if (r->u.dst.dev->nd_net != st->p.net)
+ continue;
+ if (r->rt_genid == st->genid)
+ break;
+ }
+ return r;
+}
+
static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t pos)
{
struct rtable *r = rt_cache_get_first(st);
if (r)
- while (pos && (r = rt_cache_get_next(st, r))) {
- if (r->rt_genid != st->genid)
- continue;
+ while (pos && (r = rt_cache_get_next(st, r)))
--pos;
- }
return pos ? NULL : r;
}
static int rt_cache_seq_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &rt_cache_seq_ops,
+ return seq_open_net(inode, file, &rt_cache_seq_ops,
sizeof(struct rt_cache_iter_state));
}
.open = rt_cache_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
}
#endif
-static __init int ip_rt_proc_init(struct net *net)
+static int __net_init ip_rt_do_proc_init(struct net *net)
{
struct proc_dir_entry *pde;
err1:
return -ENOMEM;
}
+
+static void __net_exit ip_rt_do_proc_exit(struct net *net)
+{
+ remove_proc_entry("rt_cache", net->proc_net_stat);
+ remove_proc_entry("rt_cache", net->proc_net);
+ remove_proc_entry("rt_acct", net->proc_net);
+}
+
+static struct pernet_operations ip_rt_proc_ops __net_initdata = {
+ .init = ip_rt_do_proc_init,
+ .exit = ip_rt_do_proc_exit,
+};
+
+static int __init ip_rt_proc_init(void)
+{
+ return register_pernet_subsys(&ip_rt_proc_ops);
+}
+
#else
-static inline int ip_rt_proc_init(struct net *net)
+static inline int ip_rt_proc_init(void)
{
return 0;
}
__be32 skeys[2] = { saddr, 0 };
int ikeys[2] = { dev->ifindex, 0 };
struct netevent_redirect netevent;
+ struct net *net;
if (!in_dev)
return;
+ net = dev->nd_net;
if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev)
|| ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw)
|| ipv4_is_zeronet(new_gw))
if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev))
goto reject_redirect;
} else {
- if (inet_addr_type(&init_net, new_gw) != RTN_UNICAST)
+ if (inet_addr_type(net, new_gw) != RTN_UNICAST)
goto reject_redirect;
}
rth->fl.fl4_src != skeys[i] ||
rth->fl.oif != ikeys[k] ||
rth->fl.iif != 0 ||
- rth->rt_genid != atomic_read(&rt_genid)) {
+ rth->rt_genid != atomic_read(&rt_genid) ||
+ rth->u.dst.dev->nd_net != net) {
rthp = &rth->u.dst.rt_next;
continue;
}
static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
{
- struct rtable *rt = (struct rtable*)dst;
+ struct rtable *rt = (struct rtable *)dst;
struct dst_entry *ret = dst;
if (rt) {
void ip_rt_send_redirect(struct sk_buff *skb)
{
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
struct in_device *in_dev = in_dev_get(rt->u.dst.dev);
if (!in_dev)
static int ip_error(struct sk_buff *skb)
{
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
unsigned long now;
int code;
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
- rt = (struct rtable *) skb->dst;
+ rt = skb->rtable;
if (rt)
dst_set_expires(&rt->u.dst, 0);
}
in_dev_put(in_dev);
hash = rt_hash(daddr, saddr, dev->ifindex);
- return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);
+ return rt_intern_hash(hash, rth, &skb->rtable);
e_nobufs:
in_dev_put(in_dev);
/* put it into the cache */
hash = rt_hash(daddr, saddr, fl->iif);
- return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+ return rt_intern_hash(hash, rth, &skb->rtable);
}
/*
}
rth->rt_type = res.type;
hash = rt_hash(daddr, saddr, fl.iif);
- err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+ err = rt_intern_hash(hash, rth, &skb->rtable);
goto done;
no_route:
dst_use(&rth->u.dst, jiffies);
RT_CACHE_STAT_INC(in_hit);
rcu_read_unlock();
- skb->dst = (struct dst_entry*)rth;
+ skb->rtable = rth;
return 0;
}
RT_CACHE_STAT_INC(in_hlist_search);
static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
int nowait, unsigned int flags)
{
- struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt = skb->rtable;
struct rtmsg *r;
struct nlmsghdr *nlh;
long expires;
int err;
struct sk_buff *skb;
- if (net != &init_net)
- return -EINVAL;
-
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
if (err < 0)
goto errout;
if (iif) {
struct net_device *dev;
- dev = __dev_get_by_index(&init_net, iif);
+ dev = __dev_get_by_index(net, iif);
if (dev == NULL) {
err = -ENODEV;
goto errout_free;
err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
local_bh_enable();
- rt = (struct rtable*) skb->dst;
+ rt = skb->rtable;
if (err == 0 && rt->u.dst.error)
err = -rt->u.dst.error;
} else {
},
.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
};
- err = ip_route_output_key(&init_net, &rt, &fl);
+ err = ip_route_output_key(net, &rt, &fl);
}
if (err)
goto errout_free;
- skb->dst = &rt->u.dst;
+ skb->rtable = rt;
if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY;
err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
- RTM_NEWROUTE, 0, 0);
+ RTM_NEWROUTE, 0, 0);
if (err <= 0)
goto errout_free;
- err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
+ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
errout:
return err;
struct rtable *rt;
int h, s_h;
int idx, s_idx;
+ struct net *net;
+
+ net = skb->sk->sk_net;
s_h = cb->args[0];
if (s_h < 0)
rcu_read_lock_bh();
for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt;
rt = rcu_dereference(rt->u.dst.rt_next), idx++) {
- if (idx < s_idx)
+ if (rt->u.dst.dev->nd_net != net || idx < s_idx)
continue;
if (rt->rt_genid != atomic_read(&rt_genid))
continue;
ip_rt_secret_interval;
add_timer(&rt_secret_timer);
- if (ip_rt_proc_init(&init_net))
+ if (ip_rt_proc_init())
printk(KERN_ERR "Unable to create route proc files\n");
#ifdef CONFIG_XFRM
xfrm_init();
* 2 of the License, or (at your option) any later version.
*
* $Id: syncookies.c,v 1.18 2002/02/01 22:01:04 davem Exp $
- *
- * Missing: IPv6 support.
*/
#include <linux/tcp.h>
extern int sysctl_tcp_syncookies;
-static __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
+__u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
+EXPORT_SYMBOL(syncookie_secret);
static __init int init_syncookies(void)
{
get_random_bytes(syncookie_secret, sizeof(syncookie_secret));
return 0;
}
-module_init(init_syncookies);
+__initcall(init_syncookies);
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+
static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
u32 count, int c)
{
- __u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS];
+ __u32 *tmp = __get_cpu_var(cookie_scratch);
memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c]));
tmp[0] = (__force u32)saddr;
/*
- * TCP CUBIC: Binary Increase Congestion control for TCP v2.1
- *
+ * TCP CUBIC: Binary Increase Congestion control for TCP v2.2
+ * Home page:
+ * http://netsrv.csc.ncsu.edu/twiki/bin/view/Main/BIC
* This is from the implementation of CUBIC TCP in
* Injong Rhee, Lisong Xu.
* "CUBIC: A New TCP-Friendly High-Speed TCP Variant
* in PFLDnet 2005
* Available from:
- * http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/cubic-paper.pdf
+ * http://netsrv.csc.ncsu.edu/export/cubic-paper.pdf
*
* Unless CUBIC is enabled and congestion window is large
* this behaves the same as the original Reno.
#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation
* max_cwnd = snd_cwnd * beta
*/
-#define BICTCP_B 4 /*
- * In binary search,
- * go to point (max+min)/N
- */
#define BICTCP_HZ 10 /* BIC HZ 2^10 = 1024 */
static int fast_convergence __read_mostly = 1;
-static int max_increment __read_mostly = 16;
-static int beta __read_mostly = 819; /* = 819/1024 (BICTCP_BETA_SCALE) */
+static int beta __read_mostly = 717; /* = 717/1024 (BICTCP_BETA_SCALE) */
static int initial_ssthresh __read_mostly;
static int bic_scale __read_mostly = 41;
static int tcp_friendliness __read_mostly = 1;
/* Note parameters that are used for precomputing scale factors are read-only */
module_param(fast_convergence, int, 0644);
MODULE_PARM_DESC(fast_convergence, "turn on/off fast convergence");
-module_param(max_increment, int, 0644);
-MODULE_PARM_DESC(max_increment, "Limit on increment allowed during binary search");
-module_param(beta, int, 0444);
+module_param(beta, int, 0644);
MODULE_PARM_DESC(beta, "beta for multiplicative increase");
module_param(initial_ssthresh, int, 0644);
MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold");
static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
{
u64 offs;
- u32 delta, t, bic_target, min_cnt, max_cnt;
+ u32 delta, t, bic_target, max_cnt;
ca->ack_cnt++; /* count the number of ACKs */
ca->cnt = 100 * cwnd; /* very small increment*/
}
- if (ca->delay_min > 0) {
- /* max increment = Smax * rtt / 0.1 */
- min_cnt = (cwnd * HZ * 8)/(10 * max_increment * ca->delay_min);
-
- /* use concave growth when the target is above the origin */
- if (ca->cnt < min_cnt && t >= ca->bic_K)
- ca->cnt = min_cnt;
- }
-
- /* slow start and low utilization */
- if (ca->loss_cwnd == 0) /* could be aggressive in slow start */
- ca->cnt = 50;
-
/* TCP Friendly */
if (tcp_friendliness) {
u32 scale = beta_scale;
MODULE_AUTHOR("Sangtae Ha, Stephen Hemminger");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CUBIC TCP");
-MODULE_VERSION("2.1");
+MODULE_VERSION("2.2");
* cases we should never reach this piece of code.
*/
printk(KERN_ERR "%s: Impossible, sk->sk_state=%d\n",
- __FUNCTION__, sk->sk_state);
+ __func__, sk->sk_state);
break;
}
EXPORT_SYMBOL(sysctl_tcp_ecn);
EXPORT_SYMBOL(sysctl_tcp_reordering);
+EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
EXPORT_SYMBOL(tcp_parse_options);
EXPORT_SYMBOL(tcp_rcv_established);
EXPORT_SYMBOL(tcp_rcv_state_process);
if (th->rst)
return;
- if (((struct rtable *)skb->dst)->rt_type != RTN_LOCAL)
+ if (skb->rtable->rt_type != RTN_LOCAL)
return;
/* Swap the send and the receive. */
* This still operates on a request_sock only, not on a big
* socket.
*/
-static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
- struct dst_entry *dst)
+static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
+ struct dst_entry *dst)
{
const struct inet_request_sock *ireq = inet_rsk(req);
int err = -1;
/* First, grab a route. */
if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)
- goto out;
+ return -1;
skb = tcp_make_synack(sk, dst, req);
err = net_xmit_eval(err);
}
-out:
dst_release(dst);
return err;
}
+static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req)
+{
+ return __tcp_v4_send_synack(sk, req, NULL);
+}
+
/*
* IPv4 request_sock destructor.
*/
#endif
/* Never answer to SYNs send to broadcast or multicast */
- if (((struct rtable *)skb->dst)->rt_flags &
- (RTCF_BROADCAST | RTCF_MULTICAST))
+ if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
goto drop;
/* TW buckets are converted to open requests without
(s32)(peer->tcp_ts - req->ts_recent) >
TCP_PAWS_WINDOW) {
NET_INC_STATS_BH(LINUX_MIB_PAWSPASSIVEREJECTED);
- dst_release(dst);
- goto drop_and_free;
+ goto drop_and_release;
}
}
/* Kill the following clause, if you dislike this way. */
"request from %u.%u.%u.%u/%u\n",
NIPQUAD(saddr),
ntohs(tcp_hdr(skb)->source));
- dst_release(dst);
- goto drop_and_free;
+ goto drop_and_release;
}
isn = tcp_v4_init_sequence(skb);
}
tcp_rsk(req)->snt_isn = isn;
- if (tcp_v4_send_synack(sk, req, dst))
+ if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)
goto drop_and_free;
- if (want_cookie) {
- reqsk_free(req);
- } else {
- inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
- }
+ inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
return 0;
+drop_and_release:
+ dst_release(dst);
drop_and_free:
reqsk_free(req);
drop:
REF_PROTO_INUSE(tcp)
};
-void __init tcp_v4_init(struct net_proto_family *ops)
+void __init tcp_v4_init(void)
{
if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW,
IPPROTO_TCP) < 0)
#endif
int sysctl_tcp_syncookies __read_mostly = SYNC_INIT;
+EXPORT_SYMBOL(sysctl_tcp_syncookies);
+
int sysctl_tcp_abort_on_overflow __read_mostly;
struct inet_timewait_death_row tcp_death_row = {
* Enforce "SYN-ACK" according to figure 8, figure 6
* of RFC793, fixed by RFC1122.
*/
- req->rsk_ops->rtx_syn_ack(sk, req, NULL);
+ req->rsk_ops->rtx_syn_ack(sk, req);
return NULL;
}
}
}
+EXPORT_SYMBOL(tcp_select_initial_window);
EXPORT_SYMBOL(tcp_connect);
EXPORT_SYMBOL(tcp_make_synack);
EXPORT_SYMBOL(tcp_simple_retransmit);
#ifdef CONFIG_PROC_FS
if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */
- printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__);
+ printk(KERN_ERR "%s: Cannot register /proc!\n", __func__);
#endif
return;
out_unregister_proto:
proto_unregister(&udplite_prot);
out_register_err:
- printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__);
+ printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__);
}
EXPORT_SYMBOL(udplite_hash);
ipv6-$(CONFIG_NETFILTER) += netfilter.o
ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
ipv6-$(CONFIG_PROC_FS) += proc.o
+ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o
ipv6-objs += $(ipv6-y)
if (snmp6_alloc_dev(ndev) < 0) {
ADBG((KERN_WARNING
"%s(): cannot allocate memory for statistics; dev=%s.\n",
- __FUNCTION__, dev->name));
+ __func__, dev->name));
neigh_parms_release(&nd_tbl, ndev->nd_parms);
ndev->dead = 1;
in6_dev_finish_destroy(ndev);
if (snmp6_register_dev(ndev) < 0) {
ADBG((KERN_WARNING
"%s(): cannot create /proc/net/dev_snmp6/%s\n",
- __FUNCTION__, dev->name));
+ __func__, dev->name));
neigh_parms_release(&nd_tbl, ndev->nd_parms);
ndev->dead = 1;
in6_dev_finish_destroy(ndev);
dev_forward_change((struct inet6_dev *)table->extra1);
if (*p)
- rt6_purge_dflt_routers();
+ rt6_purge_dflt_routers(net);
}
#endif
write_lock(&addrconf_hash_lock);
/* Ignore adding duplicate addresses on an interface */
- if (ipv6_chk_same_addr(&init_net, addr, idev->dev)) {
+ if (ipv6_chk_same_addr(idev->dev->nd_net, addr, idev->dev)) {
ADBG(("ipv6_add_addr: already assigned\n"));
err = -EEXIST;
goto out;
if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
struct in6_addr prefix;
struct rt6_info *rt;
-
+ struct net *net = ifp->idev->dev->nd_net;
ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
- rt = rt6_lookup(&prefix, NULL, ifp->idev->dev->ifindex, 1);
+ rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1);
if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
if (onlink == 0) {
{
struct ipv6_saddr_score hiscore;
struct inet6_ifaddr *ifa_result = NULL;
+ struct net *net = daddr_dev->nd_net;
int daddr_type = __ipv6_addr_type(daddr);
int daddr_scope = __ipv6_addr_src_scope(daddr_type);
int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0;
read_lock(&dev_base_lock);
rcu_read_lock();
- for_each_netdev(&init_net, dev) {
+ for_each_netdev(net, dev) {
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
if (hiscore.rule < 7)
hiscore.rule++;
#endif
+
+ /* Skip rule 8 for orchid -> non-orchid address pairs. */
+ if (ipv6_addr_orchid(&ifa->addr) && !ipv6_addr_orchid(daddr))
+ continue;
+
/* Rule 8: Use longest matching prefix */
if (hiscore.rule < 8) {
hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr);
return 0;
}
-
-int ipv6_get_saddr(struct dst_entry *dst,
- struct in6_addr *daddr, struct in6_addr *saddr)
-{
- return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr);
-}
-
-EXPORT_SYMBOL(ipv6_get_saddr);
+EXPORT_SYMBOL(ipv6_dev_get_saddr);
int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
unsigned char banned_flags)
.fc_expires = expires,
.fc_dst_len = plen,
.fc_flags = RTF_UP | flags,
- .fc_nlinfo.nl_net = &init_net,
+ .fc_nlinfo.nl_net = dev->nd_net,
};
ipv6_addr_copy(&cfg.fc_dst, pfx);
.fc_ifindex = dev->ifindex,
.fc_dst_len = 8,
.fc_flags = RTF_UP,
- .fc_nlinfo.nl_net = &init_net,
+ .fc_nlinfo.nl_net = dev->nd_net,
};
ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0);
.fc_ifindex = dev->ifindex,
.fc_dst_len = 96,
.fc_flags = RTF_UP | RTF_NONEXTHOP,
- .fc_nlinfo.nl_net = &init_net,
+ .fc_nlinfo.nl_net = dev->nd_net,
};
/* prefix length - 96 bits "::d.d.d.d" */
if (pinfo->onlink) {
struct rt6_info *rt;
- rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1);
+ rt = rt6_lookup(dev->nd_net, &pinfo->prefix, NULL,
+ dev->ifindex, 1);
if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
if (rt->rt6i_flags&RTF_EXPIRES) {
ok:
- ifp = ipv6_get_ifaddr(&init_net, &addr, dev, 1);
+ ifp = ipv6_get_ifaddr(dev->nd_net, &addr, dev, 1);
if (ifp == NULL && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
* Special case for SIT interfaces where we create a new "virtual"
* device.
*/
-int addrconf_set_dstaddr(void __user *arg)
+int addrconf_set_dstaddr(struct net *net, void __user *arg)
{
struct in6_ifreq ireq;
struct net_device *dev;
if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
goto err_exit;
- dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex);
+ dev = __dev_get_by_index(net, ireq.ifr6_ifindex);
err = -ENODEV;
if (dev == NULL)
if (err == 0) {
err = -ENOBUFS;
- if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL)
+ dev = __dev_get_by_name(net, p.name);
+ if (!dev)
goto err_exit;
err = dev_open(dev);
}
/*
* Manual configuration of address on an interface
*/
-static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
- __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft)
+static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
+ int plen, __u8 ifa_flags, __u32 prefered_lft,
+ __u32 valid_lft)
{
struct inet6_ifaddr *ifp;
struct inet6_dev *idev;
if (!valid_lft || prefered_lft > valid_lft)
return -EINVAL;
- if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL)
+ dev = __dev_get_by_index(net, ifindex);
+ if (!dev)
return -ENODEV;
if ((idev = addrconf_add_dev(dev)) == NULL)
return PTR_ERR(ifp);
}
-static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen)
+static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
+ int plen)
{
struct inet6_ifaddr *ifp;
struct inet6_dev *idev;
struct net_device *dev;
- if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL)
+ dev = __dev_get_by_index(net, ifindex);
+ if (!dev)
return -ENODEV;
if ((idev = __in6_dev_get(dev)) == NULL)
}
-int addrconf_add_ifaddr(void __user *arg)
+int addrconf_add_ifaddr(struct net *net, void __user *arg)
{
struct in6_ifreq ireq;
int err;
return -EFAULT;
rtnl_lock();
- err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
- IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
+ err = inet6_addr_add(net, ireq.ifr6_ifindex, &ireq.ifr6_addr,
+ ireq.ifr6_prefixlen, IFA_F_PERMANENT,
+ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
rtnl_unlock();
return err;
}
-int addrconf_del_ifaddr(void __user *arg)
+int addrconf_del_ifaddr(struct net *net, void __user *arg)
{
struct in6_ifreq ireq;
int err;
return -EFAULT;
rtnl_lock();
- err = inet6_addr_del(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
+ err = inet6_addr_del(net, ireq.ifr6_ifindex, &ireq.ifr6_addr,
+ ireq.ifr6_prefixlen);
rtnl_unlock();
return err;
}
struct inet6_ifaddr * ifp;
struct in6_addr addr;
struct net_device *dev;
+ struct net *net = idev->dev->nd_net;
int scope;
ASSERT_RTNL();
return;
}
- for_each_netdev(&init_net, dev) {
+ for_each_netdev(net, dev) {
struct in_device * in_dev = __in_dev_get_rtnl(dev);
if (in_dev && (dev->flags & IFF_UP)) {
struct in_ifaddr * ifa;
static void ip6_tnl_add_linklocal(struct inet6_dev *idev)
{
struct net_device *link_dev;
+ struct net *net = idev->dev->nd_net;
/* first try to inherit the link-local address from the link device */
if (idev->dev->iflink &&
- (link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) {
+ (link_dev = __dev_get_by_index(net, idev->dev->iflink))) {
if (!ipv6_inherit_linklocal(idev, link_dev))
return;
}
/* then try to inherit it from any device */
- for_each_netdev(&init_net, link_dev) {
+ for_each_netdev(net, link_dev) {
if (!ipv6_inherit_linklocal(idev, link_dev))
return;
}
int run_pending = 0;
int err;
- if (dev->nd_net != &init_net)
- return NOTIFY_DONE;
-
switch(event) {
case NETDEV_REGISTER:
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
{
struct inet6_dev *idev;
struct inet6_ifaddr *ifa, **bifa;
+ struct net *net = dev->nd_net;
int i;
ASSERT_RTNL();
if (dev == init_net.loopback_dev && how == 1)
how = 0;
- rt6_ifdown(dev);
+ rt6_ifdown(net, dev);
neigh_ifdown(&nd_tbl, dev);
idev = __in6_dev_get(dev);
struct in6_addr *pfx;
int err;
- if (net != &init_net)
- return -EINVAL;
-
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
if (err < 0)
return err;
if (pfx == NULL)
return -EINVAL;
- return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+ return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen);
}
static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
u8 ifa_flags;
int err;
- if (net != &init_net)
- return -EINVAL;
-
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
if (err < 0)
return err;
valid_lft = INFINITY_LIFE_TIME;
}
- dev = __dev_get_by_index(&init_net, ifm->ifa_index);
+ dev = __dev_get_by_index(net, ifm->ifa_index);
if (dev == NULL)
return -ENODEV;
* It would be best to check for !NLM_F_CREATE here but
* userspace alreay relies on not having to provide this.
*/
- return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
- ifa_flags, preferred_lft, valid_lft);
+ return inet6_addr_add(net, ifm->ifa_index, pfx,
+ ifm->ifa_prefixlen, ifa_flags,
+ preferred_lft, valid_lft);
}
if (nlh->nlmsg_flags & NLM_F_EXCL ||
struct inet6_ifaddr *ifa;
struct ifmcaddr6 *ifmca;
struct ifacaddr6 *ifaca;
+ struct net *net = skb->sk->sk_net;
s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];
idx = 0;
- for_each_netdev(&init_net, dev) {
+ for_each_netdev(net, dev) {
if (idx < s_idx)
goto cont;
if (idx > s_idx)
static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct net *net = skb->sk->sk_net;
enum addr_type_t type = UNICAST_ADDR;
- if (net != &init_net)
- return 0;
-
return inet6_dump_addr(skb, cb, type);
}
static int inet6_dump_ifmcaddr(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct net *net = skb->sk->sk_net;
enum addr_type_t type = MULTICAST_ADDR;
- if (net != &init_net)
- return 0;
-
return inet6_dump_addr(skb, cb, type);
}
static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct net *net = skb->sk->sk_net;
enum addr_type_t type = ANYCAST_ADDR;
- if (net != &init_net)
- return 0;
-
return inet6_dump_addr(skb, cb, type);
}
struct sk_buff *skb;
int err;
- if (net != &init_net)
- return -EINVAL;
-
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
if (err < 0)
goto errout;
ifm = nlmsg_data(nlh);
if (ifm->ifa_index)
- dev = __dev_get_by_index(&init_net, ifm->ifa_index);
+ dev = __dev_get_by_index(net, ifm->ifa_index);
if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) {
err = -EADDRNOTAVAIL;
kfree_skb(skb);
goto errout_ifa;
}
- err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
+ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
errout_ifa:
in6_ifa_put(ifa);
errout:
static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
{
struct sk_buff *skb;
+ struct net *net = ifa->idev->dev->nd_net;
int err = -ENOBUFS;
skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC);
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+ err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
- rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
+ rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
}
static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
struct net_device *dev;
struct inet6_dev *idev;
- if (net != &init_net)
- return 0;
-
read_lock(&dev_base_lock);
idx = 0;
- for_each_netdev(&init_net, dev) {
+ for_each_netdev(net, dev) {
if (idx < s_idx)
goto cont;
if ((idev = in6_dev_get(dev)) == NULL)
void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
{
struct sk_buff *skb;
+ struct net *net = idev->dev->nd_net;
int err = -ENOBUFS;
skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC);
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+ err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
- rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
+ rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
}
static inline size_t inet6_prefix_nlmsg_size(void)
struct prefix_info *pinfo)
{
struct sk_buff *skb;
+ struct net *net = idev->dev->nd_net;
int err = -ENOBUFS;
skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC);
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+ err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
errout:
if (err < 0)
- rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_PREFIX, err);
+ rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
}
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
EXPORT_SYMBOL(unregister_inet6addr_notifier);
+
+static int addrconf_net_init(struct net *net)
+{
+ return 0;
+}
+
+static void addrconf_net_exit(struct net *net)
+{
+ struct net_device *dev;
+
+ rtnl_lock();
+ /* clean dev list */
+ for_each_netdev(net, dev) {
+ if (__in6_dev_get(dev) == NULL)
+ continue;
+ addrconf_ifdown(dev, 1);
+ }
+ addrconf_ifdown(net->loopback_dev, 2);
+ rtnl_unlock();
+}
+
+static struct pernet_operations addrconf_net_ops = {
+ .init = addrconf_net_init,
+ .exit = addrconf_net_exit,
+};
+
/*
* Init / cleanup code
*/
if (err)
goto errlo;
- ip6_null_entry.u.dst.dev = init_net.loopback_dev;
- ip6_null_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- ip6_prohibit_entry.u.dst.dev = init_net.loopback_dev;
- ip6_prohibit_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
- ip6_blk_hole_entry.u.dst.dev = init_net.loopback_dev;
- ip6_blk_hole_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
-#endif
+ err = register_pernet_device(&addrconf_net_ops);
+ if (err)
+ return err;
register_netdevice_notifier(&ipv6_dev_notf);
void addrconf_cleanup(void)
{
- struct net_device *dev;
struct inet6_ifaddr *ifa;
int i;
unregister_netdevice_notifier(&ipv6_dev_notf);
+ unregister_pernet_device(&addrconf_net_ops);
unregister_pernet_subsys(&addrconf_ops);
rtnl_lock();
/*
- * clean dev list.
- */
-
- for_each_netdev(&init_net, dev) {
- if (__in6_dev_get(dev) == NULL)
- continue;
- addrconf_ifdown(dev, 1);
- }
- addrconf_ifdown(init_net.loopback_dev, 2);
-
- /*
* Check hash table.
*/
-
write_lock_bh(&addrconf_hash_lock);
for (i=0; i < IN6_ADDR_HSIZE; i++) {
for (ifa=inet6_addr_lst[i]; ifa; ) {
write_unlock_bh(&addrconf_hash_lock);
del_timer(&addr_chk_timer);
-
rtnl_unlock();
+
+ unregister_pernet_subsys(&addrconf_net_ops);
}
* ::ffff:0:0/96 V4MAPPED 4
* fc00::/7 N/A 5 ULA (RFC 4193)
* 2001::/32 N/A 6 Teredo (RFC 4380)
+ * 2001:10::/28 N/A 7 ORCHID (RFC 4843)
*
* Note: 0xffffffff is used if we do not have any policies.
*/
.prefix = &(struct in6_addr){{{ 0x20, 0x01 }}},
.prefixlen = 32,
.label = 6,
+ },{ /* 2001:10::/28 */
+ .prefix = &(struct in6_addr){{{ 0x20, 0x01, 0x00, 0x10 }}},
+ .prefixlen = 28,
+ .label = 7,
},{ /* ::ffff:0:0 */
.prefix = &(struct in6_addr){{{ [10] = 0xff, [11] = 0xff }}},
.prefixlen = 96,
rcu_read_unlock();
ADDRLABEL(KERN_DEBUG "%s(addr=" NIP6_FMT ", type=%d, ifindex=%d) => %08x\n",
- __FUNCTION__,
+ __func__,
NIP6(*addr), type, ifindex,
label);
int addrtype;
ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u)\n",
- __FUNCTION__,
+ __func__,
NIP6(*prefix), prefixlen,
ifindex,
(unsigned int)label);
int ret = 0;
ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n",
- __FUNCTION__,
+ __func__,
newp, replace);
if (hlist_empty(&ip6addrlbl_table.head)) {
int ret = 0;
ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n",
- __FUNCTION__,
+ __func__,
NIP6(*prefix), prefixlen,
ifindex,
(unsigned int)label,
int ret = -ESRCH;
ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n",
- __FUNCTION__,
+ __func__,
NIP6(*prefix), prefixlen,
ifindex);
int ret;
ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n",
- __FUNCTION__,
+ __func__,
NIP6(*prefix), prefixlen,
ifindex);
int err = 0;
int i;
- ADDRLABEL(KERN_DEBUG "%s()\n", __FUNCTION__);
+ ADDRLABEL(KERN_DEBUG "%s()\n", __func__);
for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
int ret = ip6addrlbl_add(ip6addrlbl_init_table[i].prefix,
int try_loading_module = 0;
int err;
- if (net != &init_net)
- return -EAFNOSUPPORT;
-
if (sock->type != SOCK_RAW &&
sock->type != SOCK_DGRAM &&
!inet_ehash_secret)
struct sock *sk = sock->sk;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
+ struct net *net = sk->sk_net;
__be32 v4addr = 0;
unsigned short snum;
int addr_type = 0;
/* Check if the address belongs to the host. */
if (addr_type == IPV6_ADDR_MAPPED) {
v4addr = addr->sin6_addr.s6_addr32[3];
- if (inet_addr_type(&init_net, v4addr) != RTN_LOCAL) {
+ if (inet_addr_type(net, v4addr) != RTN_LOCAL) {
err = -EADDRNOTAVAIL;
goto out;
}
err = -EINVAL;
goto out;
}
- dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
+ dev = dev_get_by_index(net, sk->sk_bound_dev_if);
if (!dev) {
err = -ENODEV;
goto out;
*/
v4addr = LOOPBACK4_IPV6;
if (!(addr_type & IPV6_ADDR_MULTICAST)) {
- if (!ipv6_chk_addr(&init_net, &addr->sin6_addr,
+ if (!ipv6_chk_addr(net, &addr->sin6_addr,
dev, 0)) {
if (dev)
dev_put(dev);
int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
+ struct net *net = sk->sk_net;
switch(cmd)
{
case SIOCADDRT:
case SIOCDELRT:
- return(ipv6_route_ioctl(cmd,(void __user *)arg));
+ return(ipv6_route_ioctl(net, cmd, (void __user *)arg));
case SIOCSIFADDR:
- return addrconf_add_ifaddr((void __user *) arg);
+ return addrconf_add_ifaddr(net, (void __user *) arg);
case SIOCDIFADDR:
- return addrconf_del_ifaddr((void __user *) arg);
+ return addrconf_del_ifaddr(net, (void __user *) arg);
case SIOCSIFDSTADDR:
- return addrconf_set_dstaddr((void __user *) arg);
+ return addrconf_set_dstaddr(net, (void __user *) arg);
default:
if (!sk->sk_prot->ioctl)
return -ENOIOCTLCMD;
EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
+static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb,
+ int proto)
+{
+ struct inet6_protocol *ops = NULL;
+
+ for (;;) {
+ struct ipv6_opt_hdr *opth;
+ int len;
+
+ if (proto != NEXTHDR_HOP) {
+ ops = rcu_dereference(inet6_protos[proto]);
+
+ if (unlikely(!ops))
+ break;
+
+ if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
+ break;
+ }
+
+ if (unlikely(!pskb_may_pull(skb, 8)))
+ break;
+
+ opth = (void *)skb->data;
+ len = ipv6_optlen(opth);
+
+ if (unlikely(!pskb_may_pull(skb, len)))
+ break;
+
+ proto = opth->nexthdr;
+ __skb_pull(skb, len);
+ }
+
+ return ops;
+}
+
+static int ipv6_gso_send_check(struct sk_buff *skb)
+{
+ struct ipv6hdr *ipv6h;
+ struct inet6_protocol *ops;
+ int err = -EINVAL;
+
+ if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
+ goto out;
+
+ ipv6h = ipv6_hdr(skb);
+ __skb_pull(skb, sizeof(*ipv6h));
+ err = -EPROTONOSUPPORT;
+
+ rcu_read_lock();
+ ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
+ if (likely(ops && ops->gso_send_check)) {
+ skb_reset_transport_header(skb);
+ err = ops->gso_send_check(skb);
+ }
+ rcu_read_unlock();
+
+out:
+ return err;
+}
+
+static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ struct ipv6hdr *ipv6h;
+ struct inet6_protocol *ops;
+
+ if (!(features & NETIF_F_V6_CSUM))
+ features &= ~NETIF_F_SG;
+
+ if (unlikely(skb_shinfo(skb)->gso_type &
+ ~(SKB_GSO_UDP |
+ SKB_GSO_DODGY |
+ SKB_GSO_TCP_ECN |
+ SKB_GSO_TCPV6 |
+ 0)))
+ goto out;
+
+ if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
+ goto out;
+
+ ipv6h = ipv6_hdr(skb);
+ __skb_pull(skb, sizeof(*ipv6h));
+ segs = ERR_PTR(-EPROTONOSUPPORT);
+
+ rcu_read_lock();
+ ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
+ if (likely(ops && ops->gso_segment)) {
+ skb_reset_transport_header(skb);
+ segs = ops->gso_segment(skb, features);
+ }
+ rcu_read_unlock();
+
+ if (unlikely(IS_ERR(segs)))
+ goto out;
+
+ for (skb = segs; skb; skb = skb->next) {
+ ipv6h = ipv6_hdr(skb);
+ ipv6h->payload_len = htons(skb->len - skb->mac_len -
+ sizeof(*ipv6h));
+ }
+
+out:
+ return segs;
+}
+
+static struct packet_type ipv6_packet_type = {
+ .type = __constant_htons(ETH_P_IPV6),
+ .func = ipv6_rcv,
+ .gso_send_check = ipv6_gso_send_check,
+ .gso_segment = ipv6_gso_segment,
+};
+
+static int __init ipv6_packet_init(void)
+{
+ dev_add_pack(&ipv6_packet_type);
+ return 0;
+}
+
+static void ipv6_packet_cleanup(void)
+{
+ dev_remove_pack(&ipv6_packet_type);
+}
+
static int __init init_ipv6_mibs(void)
{
if (snmp_mib_init((void **)ipv6_statistics,
err = register_pernet_subsys(&inet6_net_ops);
if (err)
goto register_pernet_fail;
-
-#ifdef CONFIG_SYSCTL
- err = ipv6_sysctl_register();
- if (err)
- goto sysctl_fail;
-#endif
- err = icmpv6_init(&inet6_family_ops);
+ err = icmpv6_init();
if (err)
goto icmp_fail;
- err = ndisc_init(&inet6_family_ops);
+ err = ndisc_init();
if (err)
goto ndisc_fail;
- err = igmp6_init(&inet6_family_ops);
+ err = igmp6_init();
if (err)
goto igmp_fail;
err = ipv6_netfilter_init();
err = ipv6_packet_init();
if (err)
goto ipv6_packet_fail;
+
+#ifdef CONFIG_SYSCTL
+ err = ipv6_sysctl_register();
+ if (err)
+ goto sysctl_fail;
+#endif
out:
return err;
+#ifdef CONFIG_SYSCTL
+sysctl_fail:
+ ipv6_packet_cleanup();
+#endif
ipv6_packet_fail:
tcpv6_exit();
tcpv6_fail:
ndisc_fail:
icmpv6_cleanup();
icmp_fail:
-#ifdef CONFIG_SYSCTL
- ipv6_sysctl_unregister();
-sysctl_fail:
-#endif
unregister_pernet_subsys(&inet6_net_ops);
register_pernet_fail:
cleanup_ipv6_mibs();
/* Disallow any further netlink messages */
rtnl_unregister_all(PF_INET6);
+#ifdef CONFIG_SYSCTL
+ ipv6_sysctl_unregister();
+#endif
udpv6_exit();
udplitev6_exit();
tcpv6_exit();
ndisc_cleanup();
icmpv6_cleanup();
rawv6_exit();
-#ifdef CONFIG_SYSCTL
- ipv6_sysctl_unregister();
-#endif
+
unregister_pernet_subsys(&inet6_net_ops);
cleanup_ipv6_mibs();
proto_unregister(&rawv6_prot);
if (ifindex == 0) {
struct rt6_info *rt;
- rt = rt6_lookup(addr, NULL, 0, 0);
+ rt = rt6_lookup(&init_net, addr, NULL, 0, 0);
if (rt) {
dev = rt->rt6i_dev;
dev_hold(dev);
u8 tclass;
};
-static struct fib_rules_ops fib6_rules_ops;
-
-struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
- pol_lookup_t lookup)
+struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
+ int flags, pol_lookup_t lookup)
{
struct fib_lookup_arg arg = {
.lookup_ptr = lookup,
};
- fib_rules_lookup(&fib6_rules_ops, fl, flags, &arg);
+ fib_rules_lookup(net->ipv6.fib6_rules_ops, fl, flags, &arg);
if (arg.rule)
fib_rule_put(arg.rule);
if (arg.result)
return arg.result;
- dst_hold(&ip6_null_entry.u.dst);
- return &ip6_null_entry.u.dst;
+ dst_hold(&net->ipv6.ip6_null_entry->u.dst);
+ return &net->ipv6.ip6_null_entry->u.dst;
}
static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
{
struct rt6_info *rt = NULL;
struct fib6_table *table;
+ struct net *net = rule->fr_net;
pol_lookup_t lookup = arg->lookup_ptr;
switch (rule->action) {
case FR_ACT_TO_TBL:
break;
case FR_ACT_UNREACHABLE:
- rt = &ip6_null_entry;
+ rt = net->ipv6.ip6_null_entry;
goto discard_pkt;
default:
case FR_ACT_BLACKHOLE:
- rt = &ip6_blk_hole_entry;
+ rt = net->ipv6.ip6_blk_hole_entry;
goto discard_pkt;
case FR_ACT_PROHIBIT:
- rt = &ip6_prohibit_entry;
+ rt = net->ipv6.ip6_prohibit_entry;
goto discard_pkt;
}
- table = fib6_get_table(rule->table);
+ table = fib6_get_table(net, rule->table);
if (table)
- rt = lookup(table, flp, flags);
+ rt = lookup(net, table, flp, flags);
- if (rt != &ip6_null_entry) {
+ if (rt != net->ipv6.ip6_null_entry) {
struct fib6_rule *r = (struct fib6_rule *)rule;
/*
if ((rule->flags & FIB_RULE_FIND_SADDR) &&
r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) {
struct in6_addr saddr;
- if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst,
- &saddr))
+ if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+ &flp->fl6_dst, &saddr))
goto again;
if (!ipv6_prefix_equal(&saddr, &r->src.addr,
r->src.plen))
struct nlattr **tb)
{
int err = -EINVAL;
+ struct net *net = skb->sk->sk_net;
struct fib6_rule *rule6 = (struct fib6_rule *) rule;
if (rule->action == FR_ACT_TO_TBL) {
if (rule->table == RT6_TABLE_UNSPEC)
goto errout;
- if (fib6_new_table(rule->table) == NULL) {
+ if (fib6_new_table(net, rule->table) == NULL) {
err = -ENOBUFS;
goto errout;
}
+ nla_total_size(16); /* src */
}
-static struct fib_rules_ops fib6_rules_ops = {
+static struct fib_rules_ops fib6_rules_ops_template = {
.family = AF_INET6,
.rule_size = sizeof(struct fib6_rule),
.addr_size = sizeof(struct in6_addr),
.nlmsg_payload = fib6_rule_nlmsg_payload,
.nlgroup = RTNLGRP_IPV6_RULE,
.policy = fib6_rule_policy,
- .rules_list = LIST_HEAD_INIT(fib6_rules_ops.rules_list),
.owner = THIS_MODULE,
.fro_net = &init_net,
};
-static int __init fib6_default_rules_init(void)
+static int fib6_rules_net_init(struct net *net)
{
- int err;
+ int err = -ENOMEM;
- err = fib_default_rule_add(&fib6_rules_ops, 0,
- RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
- if (err < 0)
- return err;
- err = fib_default_rule_add(&fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0);
- if (err < 0)
- return err;
- return 0;
-}
+ net->ipv6.fib6_rules_ops = kmemdup(&fib6_rules_ops_template,
+ sizeof(*net->ipv6.fib6_rules_ops),
+ GFP_KERNEL);
+ if (!net->ipv6.fib6_rules_ops)
+ goto out;
-int __init fib6_rules_init(void)
-{
- int ret;
+ net->ipv6.fib6_rules_ops->fro_net = net;
+ INIT_LIST_HEAD(&net->ipv6.fib6_rules_ops->rules_list);
- ret = fib6_default_rules_init();
- if (ret)
- goto out;
+ err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0,
+ RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
+ if (err)
+ goto out_fib6_rules_ops;
- ret = fib_rules_register(&fib6_rules_ops);
- if (ret)
- goto out_default_rules_init;
+ err = fib_default_rule_add(net->ipv6.fib6_rules_ops,
+ 0x7FFE, RT6_TABLE_MAIN, 0);
+ if (err)
+ goto out_fib6_default_rule_add;
+
+ err = fib_rules_register(net->ipv6.fib6_rules_ops);
+ if (err)
+ goto out_fib6_default_rule_add;
out:
- return ret;
+ return err;
-out_default_rules_init:
- fib_rules_cleanup_ops(&fib6_rules_ops);
+out_fib6_default_rule_add:
+ fib_rules_cleanup_ops(net->ipv6.fib6_rules_ops);
+out_fib6_rules_ops:
+ kfree(net->ipv6.fib6_rules_ops);
goto out;
}
+static void fib6_rules_net_exit(struct net *net)
+{
+ fib_rules_unregister(net->ipv6.fib6_rules_ops);
+ kfree(net->ipv6.fib6_rules_ops);
+}
+
+static struct pernet_operations fib6_rules_net_ops = {
+ .init = fib6_rules_net_init,
+ .exit = fib6_rules_net_exit,
+};
+
+int __init fib6_rules_init(void)
+{
+ return register_pernet_subsys(&fib6_rules_net_ops);
+}
+
+
void fib6_rules_cleanup(void)
{
- fib_rules_unregister(&fib6_rules_ops);
+ return unregister_pernet_subsys(&fib6_rules_net_ops);
}
*
* On SMP we have one ICMP socket per-cpu.
*/
-static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL;
-#define icmpv6_socket __get_cpu_var(__icmpv6_socket)
+static inline struct sock *icmpv6_sk(struct net *net)
+{
+ return net->ipv6.icmp_sk[smp_processor_id()];
+}
static int icmpv6_rcv(struct sk_buff *skb);
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
-static __inline__ int icmpv6_xmit_lock(void)
+static __inline__ int icmpv6_xmit_lock(struct sock *sk)
{
local_bh_disable();
- if (unlikely(!spin_trylock(&icmpv6_socket->sk->sk_lock.slock))) {
+ if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
/* This can happen if the output path (f.e. SIT or
* ip6ip6 tunnel) signals dst_link_failure() for an
* outgoing ICMP6 packet.
return 0;
}
-static __inline__ void icmpv6_xmit_unlock(void)
+static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
{
- spin_unlock_bh(&icmpv6_socket->sk->sk_lock.slock);
+ spin_unlock_bh(&sk->sk_lock.slock);
}
/*
struct flowi *fl)
{
struct dst_entry *dst;
+ struct net *net = sk->sk_net;
int res = 0;
/* Informational messages are not limited. */
* XXX: perhaps the expire for routing entries cloned by
* this lookup should be more aggressive (not longer than timeout).
*/
- dst = ip6_route_output(sk, fl);
+ dst = ip6_route_output(net, sk, fl);
if (dst->error) {
IP6_INC_STATS(ip6_dst_idev(dst),
IPSTATS_MIB_OUTNOROUTES);
res = 1;
} else {
struct rt6_info *rt = (struct rt6_info *)dst;
- int tmo = init_net.ipv6.sysctl.icmpv6_time;
+ int tmo = net->ipv6.sysctl.icmpv6_time;
/* Give more bandwidth to wider prefixes. */
if (rt->rt6i_dst.plen < 128)
void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
struct net_device *dev)
{
+ struct net *net = skb->dev->nd_net;
struct inet6_dev *idev = NULL;
struct ipv6hdr *hdr = ipv6_hdr(skb);
struct sock *sk;
*/
addr_type = ipv6_addr_type(&hdr->daddr);
- if (ipv6_chk_addr(&init_net, &hdr->daddr, skb->dev, 0))
+ if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0))
saddr = &hdr->daddr;
/*
fl.fl_icmp_code = code;
security_skb_classify_flow(skb, &fl);
- if (icmpv6_xmit_lock())
- return;
-
- sk = icmpv6_socket->sk;
+ sk = icmpv6_sk(net);
np = inet6_sk(sk);
+ if (icmpv6_xmit_lock(sk))
+ return;
+
if (!icmpv6_xrlim_allow(sk, type, &fl))
goto out;
out_dst_release:
dst_release(dst);
out:
- icmpv6_xmit_unlock();
+ icmpv6_xmit_unlock(sk);
}
EXPORT_SYMBOL(icmpv6_send);
static void icmpv6_echo_reply(struct sk_buff *skb)
{
+ struct net *net = skb->dev->nd_net;
struct sock *sk;
struct inet6_dev *idev;
struct ipv6_pinfo *np;
fl.fl_icmp_type = ICMPV6_ECHO_REPLY;
security_skb_classify_flow(skb, &fl);
- if (icmpv6_xmit_lock())
- return;
-
- sk = icmpv6_socket->sk;
+ sk = icmpv6_sk(net);
np = inet6_sk(sk);
+ if (icmpv6_xmit_lock(sk))
+ return;
+
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif;
in6_dev_put(idev);
dst_release(dst);
out:
- icmpv6_xmit_unlock();
+ icmpv6_xmit_unlock(sk);
}
static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info)
return 0;
}
+void icmpv6_flow_init(struct sock *sk, struct flowi *fl,
+ u8 type,
+ const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
+ int oif)
+{
+ memset(fl, 0, sizeof(*fl));
+ ipv6_addr_copy(&fl->fl6_src, saddr);
+ ipv6_addr_copy(&fl->fl6_dst, daddr);
+ fl->proto = IPPROTO_ICMPV6;
+ fl->fl_icmp_type = type;
+ fl->fl_icmp_code = 0;
+ fl->oif = oif;
+ security_sk_classify_flow(sk, fl);
+}
+
/*
- * Special lock-class for __icmpv6_socket:
+ * Special lock-class for __icmpv6_sk:
*/
static struct lock_class_key icmpv6_socket_sk_dst_lock_key;
-int __init icmpv6_init(struct net_proto_family *ops)
+static int __net_init icmpv6_sk_init(struct net *net)
{
struct sock *sk;
int err, i, j;
+ net->ipv6.icmp_sk =
+ kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
+ if (net->ipv6.icmp_sk == NULL)
+ return -ENOMEM;
+
for_each_possible_cpu(i) {
+ struct socket *sock;
err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6,
- &per_cpu(__icmpv6_socket, i));
+ &sock);
if (err < 0) {
printk(KERN_ERR
"Failed to initialize the ICMP6 control socket "
goto fail;
}
- sk = per_cpu(__icmpv6_socket, i)->sk;
+ net->ipv6.icmp_sk[i] = sk = sock->sk;
+ sk_change_net(sk, net);
+
sk->sk_allocation = GFP_ATOMIC;
/*
* Split off their lock-class, because sk->sk_dst_lock
* gets used from softirqs, which is safe for
- * __icmpv6_socket (because those never get directly used
+ * __icmpv6_sk (because those never get directly used
* via userspace syscalls), but unsafe for normal sockets.
*/
lockdep_set_class(&sk->sk_dst_lock,
sk->sk_prot->unhash(sk);
}
-
-
- if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) {
- printk(KERN_ERR "Failed to register ICMP6 protocol\n");
- err = -EAGAIN;
- goto fail;
- }
-
return 0;
fail:
- for (j = 0; j < i; j++) {
- if (!cpu_possible(j))
- continue;
- sock_release(per_cpu(__icmpv6_socket, j));
- }
-
+ for (j = 0; j < i; j++)
+ sk_release_kernel(net->ipv6.icmp_sk[j]);
+ kfree(net->ipv6.icmp_sk);
return err;
}
-void icmpv6_cleanup(void)
+static void __net_exit icmpv6_sk_exit(struct net *net)
{
int i;
for_each_possible_cpu(i) {
- sock_release(per_cpu(__icmpv6_socket, i));
+ sk_release_kernel(net->ipv6.icmp_sk[i]);
}
+ kfree(net->ipv6.icmp_sk);
+}
+
+static struct pernet_operations icmpv6_sk_ops = {
+ .init = icmpv6_sk_init,
+ .exit = icmpv6_sk_exit,
+};
+
+int __init icmpv6_init(void)
+{
+ int err;
+
+ err = register_pernet_subsys(&icmpv6_sk_ops);
+ if (err < 0)
+ return err;
+
+ err = -EAGAIN;
+ if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
+ goto fail;
+ return 0;
+
+fail:
+ printk(KERN_ERR "Failed to register ICMP6 protocol\n");
+ unregister_pernet_subsys(&icmpv6_sk_ops);
+ return err;
+}
+
+void icmpv6_cleanup(void)
+{
+ unregister_pernet_subsys(&icmpv6_sk_ops);
inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
}
+
static const struct icmp6_err {
int err;
int fatal;
table = kmemdup(ipv6_icmp_table_template,
sizeof(ipv6_icmp_table_template),
GFP_KERNEL);
+
+ if (table)
+ table[0].data = &net->ipv6.sysctl.icmpv6_time;
+
return table;
}
#endif
#define RT6_TRACE(x...) do { ; } while (0)
#endif
-struct rt6_statistics rt6_stats;
-
static struct kmem_cache * fib6_node_kmem __read_mostly;
enum fib_walk_state_t
struct fib6_cleaner_t
{
struct fib6_walker_t w;
+ struct net *net;
int (*func)(struct rt6_info *, void *arg);
void *arg;
};
#define FWS_INIT FWS_L
#endif
-static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
-static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
-static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
+static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
+ struct rt6_info *rt);
+static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
+static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
static int fib6_walk(struct fib6_walker_t *w);
static int fib6_walk_continue(struct fib6_walker_t *w);
static __u32 rt_sernum;
-static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0);
+static void fib6_gc_timer_cb(unsigned long arg);
static struct fib6_walker_t fib6_walker_list = {
.prev = &fib6_walker_list,
dst_free(&rt->u.dst);
}
-static struct fib6_table fib6_main_tbl = {
- .tb6_id = RT6_TABLE_MAIN,
- .tb6_root = {
- .leaf = &ip6_null_entry,
- .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
- },
-};
-
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
#define FIB_TABLE_HASHSZ 256
#else
#define FIB_TABLE_HASHSZ 1
#endif
-static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
-static void fib6_link_table(struct fib6_table *tb)
+static void fib6_link_table(struct net *net, struct fib6_table *tb)
{
unsigned int h;
* No protection necessary, this is the only list mutatation
* operation, tables never disappear once they exist.
*/
- hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
+ hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]);
}
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-static struct fib6_table fib6_local_tbl = {
- .tb6_id = RT6_TABLE_LOCAL,
- .tb6_root = {
- .leaf = &ip6_null_entry,
- .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
- },
-};
-static struct fib6_table *fib6_alloc_table(u32 id)
+static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
{
struct fib6_table *table;
table = kzalloc(sizeof(*table), GFP_ATOMIC);
if (table != NULL) {
table->tb6_id = id;
- table->tb6_root.leaf = &ip6_null_entry;
+ table->tb6_root.leaf = net->ipv6.ip6_null_entry;
table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
}
return table;
}
-struct fib6_table *fib6_new_table(u32 id)
+struct fib6_table *fib6_new_table(struct net *net, u32 id)
{
struct fib6_table *tb;
if (id == 0)
id = RT6_TABLE_MAIN;
- tb = fib6_get_table(id);
+ tb = fib6_get_table(net, id);
if (tb)
return tb;
- tb = fib6_alloc_table(id);
+ tb = fib6_alloc_table(net, id);
if (tb != NULL)
- fib6_link_table(tb);
+ fib6_link_table(net, tb);
return tb;
}
-struct fib6_table *fib6_get_table(u32 id)
+struct fib6_table *fib6_get_table(struct net *net, u32 id)
{
struct fib6_table *tb;
+ struct hlist_head *head;
struct hlist_node *node;
unsigned int h;
id = RT6_TABLE_MAIN;
h = id & (FIB_TABLE_HASHSZ - 1);
rcu_read_lock();
- hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) {
+ head = &net->ipv6.fib_table_hash[h];
+ hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
if (tb->tb6_id == id) {
rcu_read_unlock();
return tb;
return NULL;
}
-static void __init fib6_tables_init(void)
+static void fib6_tables_init(struct net *net)
{
- fib6_link_table(&fib6_main_tbl);
- fib6_link_table(&fib6_local_tbl);
+ fib6_link_table(net, net->ipv6.fib6_main_tbl);
+ fib6_link_table(net, net->ipv6.fib6_local_tbl);
}
-
#else
-struct fib6_table *fib6_new_table(u32 id)
+struct fib6_table *fib6_new_table(struct net *net, u32 id)
{
- return fib6_get_table(id);
+ return fib6_get_table(net, id);
}
-struct fib6_table *fib6_get_table(u32 id)
+struct fib6_table *fib6_get_table(struct net *net, u32 id)
{
- return &fib6_main_tbl;
+ return net->ipv6.fib6_main_tbl;
}
-struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
- pol_lookup_t lookup)
+struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
+ int flags, pol_lookup_t lookup)
{
- return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags);
+ return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
}
-static void __init fib6_tables_init(void)
+static void fib6_tables_init(struct net *net)
{
- fib6_link_table(&fib6_main_tbl);
+ fib6_link_table(net, net->ipv6.fib6_main_tbl);
}
#endif
struct fib6_walker_t *w;
struct fib6_table *tb;
struct hlist_node *node;
+ struct hlist_head *head;
int res = 0;
- if (net != &init_net)
- return 0;
-
s_h = cb->args[0];
s_e = cb->args[1];
for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
e = 0;
- hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) {
+ head = &net->ipv6.fib_table_hash[h];
+ hlist_for_each_entry(tb, node, head, tb6_hlist) {
if (e < s_e)
goto next;
res = fib6_dump_table(tb, skb, cb);
rt->rt6i_node = fn;
atomic_inc(&rt->rt6i_ref);
inet6_rt_notify(RTM_NEWROUTE, rt, info);
- rt6_stats.fib_rt_entries++;
+ info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
if ((fn->fn_flags & RTN_RTINFO) == 0) {
- rt6_stats.fib_route_nodes++;
+ info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
fn->fn_flags |= RTN_RTINFO;
}
return 0;
}
-static __inline__ void fib6_start_gc(struct rt6_info *rt)
+static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt)
{
- if (ip6_fib_timer.expires == 0 &&
+ if (net->ipv6.ip6_fib_timer->expires == 0 &&
(rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE)))
- mod_timer(&ip6_fib_timer, jiffies +
- init_net.ipv6.sysctl.ip6_rt_gc_interval);
+ mod_timer(net->ipv6.ip6_fib_timer, jiffies +
+ net->ipv6.sysctl.ip6_rt_gc_interval);
}
-void fib6_force_start_gc(void)
+void fib6_force_start_gc(struct net *net)
{
- if (ip6_fib_timer.expires == 0)
- mod_timer(&ip6_fib_timer, jiffies +
- init_net.ipv6.sysctl.ip6_rt_gc_interval);
+ if (net->ipv6.ip6_fib_timer->expires == 0)
+ mod_timer(net->ipv6.ip6_fib_timer, jiffies +
+ net->ipv6.sysctl.ip6_rt_gc_interval);
}
/*
if (sfn == NULL)
goto st_failure;
- sfn->leaf = &ip6_null_entry;
- atomic_inc(&ip6_null_entry.rt6i_ref);
+ sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
+ atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
sfn->fn_flags = RTN_ROOT;
sfn->fn_sernum = fib6_new_sernum();
err = fib6_add_rt2node(fn, rt, info);
if (err == 0) {
- fib6_start_gc(rt);
+ fib6_start_gc(info->nl_net, rt);
if (!(rt->rt6i_flags&RTF_CACHE))
- fib6_prune_clones(pn, rt);
+ fib6_prune_clones(info->nl_net, pn, rt);
}
out:
* super-tree leaf node we have to find a new one for it.
*/
if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
- pn->leaf = fib6_find_prefix(pn);
+ pn->leaf = fib6_find_prefix(info->nl_net, pn);
#if RT6_DEBUG >= 2
if (!pn->leaf) {
BUG_TRAP(pn->leaf != NULL);
- pn->leaf = &ip6_null_entry;
+ pn->leaf = info->nl_net->ipv6.ip6_null_entry;
}
#endif
atomic_inc(&pn->leaf->rt6i_ref);
*/
st_failure:
if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
- fib6_repair_tree(fn);
+ fib6_repair_tree(info->nl_net, fn);
dst_free(&rt->u.dst);
return err;
#endif
*
*/
-static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
+static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)
{
if (fn->fn_flags&RTN_ROOT)
- return &ip6_null_entry;
+ return net->ipv6.ip6_null_entry;
while(fn) {
if(fn->left)
* is the node we want to try and remove.
*/
-static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
+static struct fib6_node *fib6_repair_tree(struct net *net,
+ struct fib6_node *fn)
{
int children;
int nstate;
|| (children && fn->fn_flags&RTN_ROOT)
#endif
) {
- fn->leaf = fib6_find_prefix(fn);
+ fn->leaf = fib6_find_prefix(net, fn);
#if RT6_DEBUG >= 2
if (fn->leaf==NULL) {
BUG_TRAP(fn->leaf);
- fn->leaf = &ip6_null_entry;
+ fn->leaf = net->ipv6.ip6_null_entry;
}
#endif
atomic_inc(&fn->leaf->rt6i_ref);
{
struct fib6_walker_t *w;
struct rt6_info *rt = *rtp;
+ struct net *net = info->nl_net;
RT6_TRACE("fib6_del_route\n");
/* Unlink it */
*rtp = rt->u.dst.rt6_next;
rt->rt6i_node = NULL;
- rt6_stats.fib_rt_entries--;
- rt6_stats.fib_discarded_routes++;
+ net->ipv6.rt6_stats->fib_rt_entries--;
+ net->ipv6.rt6_stats->fib_discarded_routes++;
/* Reset round-robin state, if necessary */
if (fn->rr_ptr == rt)
/* If it was last route, expunge its radix tree node */
if (fn->leaf == NULL) {
fn->fn_flags &= ~RTN_RTINFO;
- rt6_stats.fib_route_nodes--;
- fn = fib6_repair_tree(fn);
+ net->ipv6.rt6_stats->fib_route_nodes--;
+ fn = fib6_repair_tree(net, fn);
}
if (atomic_read(&rt->rt6i_ref) != 1) {
*/
while (fn) {
if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
- fn->leaf = fib6_find_prefix(fn);
+ fn->leaf = fib6_find_prefix(net, fn);
atomic_inc(&fn->leaf->rt6i_ref);
rt6_release(rt);
}
int fib6_del(struct rt6_info *rt, struct nl_info *info)
{
+ struct net *net = info->nl_net;
struct fib6_node *fn = rt->rt6i_node;
struct rt6_info **rtp;
return -ENOENT;
}
#endif
- if (fn == NULL || rt == &ip6_null_entry)
+ if (fn == NULL || rt == net->ipv6.ip6_null_entry)
return -ENOENT;
BUG_TRAP(fn->fn_flags&RTN_RTINFO);
pn = pn->parent;
}
#endif
- fib6_prune_clones(pn, rt);
+ fib6_prune_clones(info->nl_net, pn, rt);
}
/*
static int fib6_clean_node(struct fib6_walker_t *w)
{
- struct nl_info info = {
- .nl_net = &init_net,
- };
int res;
struct rt6_info *rt;
struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w);
+ struct nl_info info = {
+ .nl_net = c->net,
+ };
for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
res = c->func(rt, c->arg);
* ignoring pure split nodes) will be scanned.
*/
-static void fib6_clean_tree(struct fib6_node *root,
+static void fib6_clean_tree(struct net *net, struct fib6_node *root,
int (*func)(struct rt6_info *, void *arg),
int prune, void *arg)
{
c.w.prune = prune;
c.func = func;
c.arg = arg;
+ c.net = net;
fib6_walk(&c.w);
}
-void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
+void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
int prune, void *arg)
{
struct fib6_table *table;
struct hlist_node *node;
+ struct hlist_head *head;
unsigned int h;
rcu_read_lock();
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
- hlist_for_each_entry_rcu(table, node, &fib_table_hash[h],
- tb6_hlist) {
+ head = &net->ipv6.fib_table_hash[h];
+ hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
write_lock_bh(&table->tb6_lock);
- fib6_clean_tree(&table->tb6_root, func, prune, arg);
+ fib6_clean_tree(net, &table->tb6_root,
+ func, prune, arg);
write_unlock_bh(&table->tb6_lock);
}
}
return 0;
}
-static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt)
+static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
+ struct rt6_info *rt)
{
- fib6_clean_tree(fn, fib6_prune_clone, 1, rt);
+ fib6_clean_tree(net, fn, fib6_prune_clone, 1, rt);
}
/*
static DEFINE_SPINLOCK(fib6_gc_lock);
-void fib6_run_gc(unsigned long dummy)
+void fib6_run_gc(unsigned long expires, struct net *net)
{
- if (dummy != ~0UL) {
+ if (expires != ~0UL) {
spin_lock_bh(&fib6_gc_lock);
- gc_args.timeout = dummy ? (int)dummy :
- init_net.ipv6.sysctl.ip6_rt_gc_interval;
+ gc_args.timeout = expires ? (int)expires :
+ net->ipv6.sysctl.ip6_rt_gc_interval;
} else {
local_bh_disable();
if (!spin_trylock(&fib6_gc_lock)) {
- mod_timer(&ip6_fib_timer, jiffies + HZ);
+ mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ);
local_bh_enable();
return;
}
- gc_args.timeout = init_net.ipv6.sysctl.ip6_rt_gc_interval;
+ gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
}
gc_args.more = 0;
- ndisc_dst_gc(&gc_args.more);
- fib6_clean_all(fib6_age, 0, NULL);
+ icmp6_dst_gc(&gc_args.more);
+
+ fib6_clean_all(net, fib6_age, 0, NULL);
if (gc_args.more)
- mod_timer(&ip6_fib_timer, jiffies +
- init_net.ipv6.sysctl.ip6_rt_gc_interval);
+ mod_timer(net->ipv6.ip6_fib_timer, jiffies +
+ net->ipv6.sysctl.ip6_rt_gc_interval);
else {
- del_timer(&ip6_fib_timer);
- ip6_fib_timer.expires = 0;
+ del_timer(net->ipv6.ip6_fib_timer);
+ net->ipv6.ip6_fib_timer->expires = 0;
}
spin_unlock_bh(&fib6_gc_lock);
}
-int __init fib6_init(void)
+static void fib6_gc_timer_cb(unsigned long arg)
+{
+ fib6_run_gc(0, (struct net *)arg);
+}
+
+static int fib6_net_init(struct net *net)
{
int ret;
+ struct timer_list *timer;
+
+ ret = -ENOMEM;
+ timer = kzalloc(sizeof(*timer), GFP_KERNEL);
+ if (!timer)
+ goto out;
+
+ setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net);
+ net->ipv6.ip6_fib_timer = timer;
+
+ net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
+ if (!net->ipv6.rt6_stats)
+ goto out_timer;
+
+ net->ipv6.fib_table_hash =
+ kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
+ GFP_KERNEL);
+ if (!net->ipv6.fib_table_hash)
+ goto out_rt6_stats;
+
+ net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
+ GFP_KERNEL);
+ if (!net->ipv6.fib6_main_tbl)
+ goto out_fib_table_hash;
+
+ net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
+ net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
+ net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
+ RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl),
+ GFP_KERNEL);
+ if (!net->ipv6.fib6_local_tbl)
+ goto out_fib6_main_tbl;
+ net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
+ net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
+ net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
+ RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+#endif
+ fib6_tables_init(net);
+
+ ret = 0;
+out:
+ return ret;
+
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+out_fib6_main_tbl:
+ kfree(net->ipv6.fib6_main_tbl);
+#endif
+out_fib_table_hash:
+ kfree(net->ipv6.fib_table_hash);
+out_rt6_stats:
+ kfree(net->ipv6.rt6_stats);
+out_timer:
+ kfree(timer);
+ goto out;
+ }
+
+static void fib6_net_exit(struct net *net)
+{
+ rt6_ifdown(net, NULL);
+ del_timer(net->ipv6.ip6_fib_timer);
+ kfree(net->ipv6.ip6_fib_timer);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ kfree(net->ipv6.fib6_local_tbl);
+#endif
+ kfree(net->ipv6.fib6_main_tbl);
+ kfree(net->ipv6.fib_table_hash);
+ kfree(net->ipv6.rt6_stats);
+}
+
+static struct pernet_operations fib6_net_ops = {
+ .init = fib6_net_init,
+ .exit = fib6_net_exit,
+};
+
+int __init fib6_init(void)
+{
+ int ret = -ENOMEM;
+
fib6_node_kmem = kmem_cache_create("fib6_nodes",
sizeof(struct fib6_node),
0, SLAB_HWCACHE_ALIGN,
NULL);
if (!fib6_node_kmem)
- return -ENOMEM;
+ goto out;
- fib6_tables_init();
+ ret = register_pernet_subsys(&fib6_net_ops);
+ if (ret)
+ goto out_kmem_cache_create;
ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
if (ret)
- goto out_kmem_cache_create;
+ goto out_unregister_subsys;
out:
return ret;
+out_unregister_subsys:
+ unregister_pernet_subsys(&fib6_net_ops);
out_kmem_cache_create:
kmem_cache_destroy(fib6_node_kmem);
goto out;
void fib6_gc_cleanup(void)
{
- del_timer(&ip6_fib_timer);
+ unregister_pernet_subsys(&fib6_net_ops);
kmem_cache_destroy(fib6_node_kmem);
}
u32 pkt_len;
struct inet6_dev *idev;
- if (dev->nd_net != &init_net) {
- kfree_skb(skb);
- return 0;
- }
-
if (skb->pkt_type == PACKET_OTHERHOST) {
kfree_skb(skb);
return 0;
struct dst_entry *dst = skb->dst;
struct ipv6hdr *hdr = ipv6_hdr(skb);
struct inet6_skb_parm *opt = IP6CB(skb);
+ struct net *net = dst->dev->nd_net;
if (ipv6_devconf.forwarding == 0)
goto error;
/* XXX: idev->cnf.proxy_ndp? */
if (ipv6_devconf.proxy_ndp &&
- pneigh_lookup(&nd_tbl, &init_net, &hdr->daddr, skb->dev, 0)) {
+ pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
int proxied = ip6_forward_proxy_check(skb);
if (proxied > 0)
return ip6_input(skb);
return offset;
}
-EXPORT_SYMBOL_GPL(ip6_find_1stfragopt);
static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
struct dst_entry **dst, struct flowi *fl)
{
int err;
+ struct net *net = sk->sk_net;
if (*dst == NULL)
- *dst = ip6_route_output(sk, fl);
+ *dst = ip6_route_output(net, sk, fl);
if ((err = (*dst)->error))
goto out_err_release;
if (ipv6_addr_any(&fl->fl6_src)) {
- err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src);
+ err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev,
+ &fl->fl6_dst, &fl->fl6_src);
if (err)
goto out_err_release;
}
struct flowi fl_gw;
int redirect;
- ifp = ipv6_get_ifaddr(&init_net, &fl->fl6_src,
+ ifp = ipv6_get_ifaddr(net, &fl->fl6_src,
(*dst)->dev, 1);
redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
dst_release(*dst);
memcpy(&fl_gw, fl, sizeof(struct flowi));
memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
- *dst = ip6_route_output(sk, &fl_gw);
+ *dst = ip6_route_output(net, sk, &fl_gw);
if ((err = (*dst)->error))
goto out_err_release;
}
#define IPV6_TLV_TEL_DST_SIZE 8
#ifdef IP6_TNL_DEBUG
-#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
+#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__)
#else
#define IP6_TNL_TRACE(x...) do {;} while(0)
#endif
skb_reset_network_header(skb2);
/* Try to guess incoming interface */
- rt = rt6_lookup(&ipv6_hdr(skb2)->saddr, NULL, 0, 0);
+ rt = rt6_lookup(&init_net, &ipv6_hdr(skb2)->saddr, NULL, 0, 0);
if (rt && rt->rt6i_dev)
skb2->dev = rt->rt6i_dev;
if ((dst = ip6_tnl_dst_check(t)) != NULL)
dst_hold(dst);
else {
- dst = ip6_route_output(NULL, fl);
+ dst = ip6_route_output(&init_net, NULL, fl);
if (dst->error || xfrm_lookup(&dst, fl, NULL, 0) < 0)
goto tx_err_link_failure;
int strict = (ipv6_addr_type(&p->raddr) &
(IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
- struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
+ struct rt6_info *rt = rt6_lookup(&init_net, &p->raddr, &p->laddr,
p->link, strict);
if (rt == NULL)
DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
-static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb,
- int proto)
-{
- struct inet6_protocol *ops = NULL;
-
- for (;;) {
- struct ipv6_opt_hdr *opth;
- int len;
-
- if (proto != NEXTHDR_HOP) {
- ops = rcu_dereference(inet6_protos[proto]);
-
- if (unlikely(!ops))
- break;
-
- if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
- break;
- }
-
- if (unlikely(!pskb_may_pull(skb, 8)))
- break;
-
- opth = (void *)skb->data;
- len = opth->hdrlen * 8 + 8;
-
- if (unlikely(!pskb_may_pull(skb, len)))
- break;
-
- proto = opth->nexthdr;
- __skb_pull(skb, len);
- }
-
- return ops;
-}
-
-static int ipv6_gso_send_check(struct sk_buff *skb)
-{
- struct ipv6hdr *ipv6h;
- struct inet6_protocol *ops;
- int err = -EINVAL;
-
- if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
- goto out;
-
- ipv6h = ipv6_hdr(skb);
- __skb_pull(skb, sizeof(*ipv6h));
- err = -EPROTONOSUPPORT;
-
- rcu_read_lock();
- ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
- if (likely(ops && ops->gso_send_check)) {
- skb_reset_transport_header(skb);
- err = ops->gso_send_check(skb);
- }
- rcu_read_unlock();
-
-out:
- return err;
-}
-
-static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
-{
- struct sk_buff *segs = ERR_PTR(-EINVAL);
- struct ipv6hdr *ipv6h;
- struct inet6_protocol *ops;
-
- if (!(features & NETIF_F_V6_CSUM))
- features &= ~NETIF_F_SG;
-
- if (unlikely(skb_shinfo(skb)->gso_type &
- ~(SKB_GSO_UDP |
- SKB_GSO_DODGY |
- SKB_GSO_TCP_ECN |
- SKB_GSO_TCPV6 |
- 0)))
- goto out;
-
- if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
- goto out;
-
- ipv6h = ipv6_hdr(skb);
- __skb_pull(skb, sizeof(*ipv6h));
- segs = ERR_PTR(-EPROTONOSUPPORT);
-
- rcu_read_lock();
- ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
- if (likely(ops && ops->gso_segment)) {
- skb_reset_transport_header(skb);
- segs = ops->gso_segment(skb, features);
- }
- rcu_read_unlock();
-
- if (unlikely(IS_ERR(segs)))
- goto out;
-
- for (skb = segs; skb; skb = skb->next) {
- ipv6h = ipv6_hdr(skb);
- ipv6h->payload_len = htons(skb->len - skb->mac_len -
- sizeof(*ipv6h));
- }
-
-out:
- return segs;
-}
-
-static struct packet_type ipv6_packet_type = {
- .type = __constant_htons(ETH_P_IPV6),
- .func = ipv6_rcv,
- .gso_send_check = ipv6_gso_send_check,
- .gso_segment = ipv6_gso_segment,
-};
-
struct ip6_ra_chain *ip6_ra_chain;
DEFINE_RWLOCK(ip6_ra_lock);
char __user *optval, int optlen)
{
struct ipv6_pinfo *np = inet6_sk(sk);
+ struct net *net = sk->sk_net;
int val, valbool;
int retv = -ENOPROTOOPT;
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
goto e_inval;
- if (__dev_get_by_index(&init_net, val) == NULL) {
+ if (__dev_get_by_index(net, val) == NULL) {
retv = -ENODEV;
break;
}
EXPORT_SYMBOL(compat_ipv6_getsockopt);
#endif
-int __init ipv6_packet_init(void)
-{
- dev_add_pack(&ipv6_packet_type);
- return 0;
-}
-
-void ipv6_packet_cleanup(void)
-{
- dev_remove_pack(&ipv6_packet_type);
-}
/* Big mc list lock for all the sockets */
static DEFINE_RWLOCK(ipv6_sk_mc_lock);
-static struct socket *igmp6_socket;
-
int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr);
static void igmp6_join_group(struct ifmcaddr6 *ma);
struct net_device *dev = NULL;
struct ipv6_mc_socklist *mc_lst;
struct ipv6_pinfo *np = inet6_sk(sk);
+ struct net *net = sk->sk_net;
int err;
if (!ipv6_addr_is_multicast(addr))
if (ifindex == 0) {
struct rt6_info *rt;
- rt = rt6_lookup(addr, NULL, 0, 0);
+ rt = rt6_lookup(net, addr, NULL, 0, 0);
if (rt) {
dev = rt->rt6i_dev;
dev_hold(dev);
dst_release(&rt->u.dst);
}
} else
- dev = dev_get_by_index(&init_net, ifindex);
+ dev = dev_get_by_index(net, ifindex);
if (dev == NULL) {
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6_mc_socklist *mc_lst, **lnk;
+ struct net *net = sk->sk_net;
write_lock_bh(&ipv6_sk_mc_lock);
for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
*lnk = mc_lst->next;
write_unlock_bh(&ipv6_sk_mc_lock);
- if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) {
+ dev = dev_get_by_index(net, mc_lst->ifindex);
+ if (dev != NULL) {
struct inet6_dev *idev = in6_dev_get(dev);
(void) ip6_mc_leave_src(sk, mc_lst, idev);
return -EADDRNOTAVAIL;
}
-static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex)
+static struct inet6_dev *ip6_mc_find_dev(struct net *net,
+ struct in6_addr *group,
+ int ifindex)
{
struct net_device *dev = NULL;
struct inet6_dev *idev = NULL;
if (ifindex == 0) {
struct rt6_info *rt;
- rt = rt6_lookup(group, NULL, 0, 0);
+ rt = rt6_lookup(net, group, NULL, 0, 0);
if (rt) {
dev = rt->rt6i_dev;
dev_hold(dev);
dst_release(&rt->u.dst);
}
} else
- dev = dev_get_by_index(&init_net, ifindex);
+ dev = dev_get_by_index(net, ifindex);
if (!dev)
return NULL;
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6_mc_socklist *mc_lst;
+ struct net *net = sk->sk_net;
write_lock_bh(&ipv6_sk_mc_lock);
while ((mc_lst = np->ipv6_mc_list) != NULL) {
np->ipv6_mc_list = mc_lst->next;
write_unlock_bh(&ipv6_sk_mc_lock);
- dev = dev_get_by_index(&init_net, mc_lst->ifindex);
+ dev = dev_get_by_index(net, mc_lst->ifindex);
if (dev) {
struct inet6_dev *idev = in6_dev_get(dev);
struct inet6_dev *idev;
struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *psl;
+ struct net *net = sk->sk_net;
int i, j, rv;
int leavegroup = 0;
int pmclocked = 0;
if (!ipv6_addr_is_multicast(group))
return -EINVAL;
- idev = ip6_mc_find_dev(group, pgsr->gsr_interface);
+ idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface);
if (!idev)
return -ENODEV;
dev = idev->dev;
struct inet6_dev *idev;
struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *newpsl, *psl;
+ struct net *net = sk->sk_net;
int leavegroup = 0;
int i, err;
gsf->gf_fmode != MCAST_EXCLUDE)
return -EINVAL;
- idev = ip6_mc_find_dev(group, gsf->gf_interface);
+ idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
if (!idev)
return -ENODEV;
struct net_device *dev;
struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *psl;
+ struct net *net = sk->sk_net;
group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
if (!ipv6_addr_is_multicast(group))
return -EINVAL;
- idev = ip6_mc_find_dev(group, gsf->gf_interface);
+ idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
if (!idev)
return -ENODEV;
static struct sk_buff *mld_newpack(struct net_device *dev, int size)
{
- struct sock *sk = igmp6_socket->sk;
+ struct net *net = dev->nd_net;
+ struct sock *sk = net->ipv6.igmp_sk;
struct sk_buff *skb;
struct mld2_report *pmr;
struct in6_addr addr_buf;
return skb;
}
-static inline int mld_dev_queue_xmit2(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- unsigned char ha[MAX_ADDR_LEN];
-
- ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1);
- if (dev_hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len) < 0) {
- kfree_skb(skb);
- return -EINVAL;
- }
- return dev_queue_xmit(skb);
-}
-
-static inline int mld_dev_queue_xmit(struct sk_buff *skb)
-{
- return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev,
- mld_dev_queue_xmit2);
-}
-
static void mld_sendpack(struct sk_buff *skb)
{
struct ipv6hdr *pip6 = ipv6_hdr(skb);
(struct mld2_report *)skb_transport_header(skb);
int payload_len, mldlen;
struct inet6_dev *idev = in6_dev_get(skb->dev);
+ struct net *net = skb->dev->nd_net;
int err;
+ struct flowi fl;
IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb),
mldlen, 0));
+
+ skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
+
+ if (!skb->dst) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ icmpv6_flow_init(net->ipv6.igmp_sk, &fl, ICMPV6_MLD2_REPORT,
+ &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+ skb->dev->ifindex);
+
+ err = xfrm_lookup(&skb->dst, &fl, NULL, 0);
+ if (err)
+ goto err_out;
+
err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
- mld_dev_queue_xmit);
+ dst_output);
+out:
if (!err) {
ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT);
ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
if (likely(idev != NULL))
in6_dev_put(idev);
+ return;
+
+err_out:
+ kfree_skb(skb);
+ goto out;
}
static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel)
static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
{
- struct sock *sk = igmp6_socket->sk;
+ struct net *net = dev->nd_net;
+ struct sock *sk = net->ipv6.igmp_sk;
struct inet6_dev *idev;
struct sk_buff *skb;
struct icmp6hdr *hdr;
u8 ra[8] = { IPPROTO_ICMPV6, 0,
IPV6_TLV_ROUTERALERT, 2, 0, 0,
IPV6_TLV_PADN, 0 };
+ struct flowi fl;
rcu_read_lock();
IP6_INC_STATS(__in6_dev_get(dev),
idev = in6_dev_get(skb->dev);
+ skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
+ if (!skb->dst) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ icmpv6_flow_init(sk, &fl, type,
+ &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+ skb->dev->ifindex);
+
+ err = xfrm_lookup(&skb->dst, &fl, NULL, 0);
+ if (err)
+ goto err_out;
+
err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
- mld_dev_queue_xmit);
+ dst_output);
+out:
if (!err) {
ICMP6MSGOUT_INC_STATS(idev, type);
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
if (likely(idev != NULL))
in6_dev_put(idev);
return;
+
+err_out:
+ kfree_skb(skb);
+ goto out;
}
static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
#ifdef CONFIG_PROC_FS
struct igmp6_mc_iter_state {
+ struct seq_net_private p;
struct net_device *dev;
struct inet6_dev *idev;
};
{
struct ifmcaddr6 *im = NULL;
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
+ struct net *net = state->p.net;
state->idev = NULL;
- for_each_netdev(&init_net, state->dev) {
+ for_each_netdev(net, state->dev) {
struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (!idev)
static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &igmp6_mc_seq_ops,
- sizeof(struct igmp6_mc_iter_state));
+ return seq_open_net(inode, file, &igmp6_mc_seq_ops,
+ sizeof(struct igmp6_mc_iter_state));
}
static const struct file_operations igmp6_mc_seq_fops = {
.open = igmp6_mc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
struct igmp6_mcf_iter_state {
+ struct seq_net_private p;
struct net_device *dev;
struct inet6_dev *idev;
struct ifmcaddr6 *im;
struct ip6_sf_list *psf = NULL;
struct ifmcaddr6 *im = NULL;
struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
+ struct net *net = state->p.net;
state->idev = NULL;
state->im = NULL;
- for_each_netdev(&init_net, state->dev) {
+ for_each_netdev(net, state->dev) {
struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (unlikely(idev == NULL))
static int igmp6_mcf_seq_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &igmp6_mcf_seq_ops,
- sizeof(struct igmp6_mcf_iter_state));
+ return seq_open_net(inode, file, &igmp6_mcf_seq_ops,
+ sizeof(struct igmp6_mcf_iter_state));
}
static const struct file_operations igmp6_mcf_seq_fops = {
.open = igmp6_mcf_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif
-int __init igmp6_init(struct net_proto_family *ops)
+static int igmp6_net_init(struct net *net)
{
struct ipv6_pinfo *np;
+ struct socket *sock;
struct sock *sk;
int err;
- err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket);
+ err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock);
if (err < 0) {
printk(KERN_ERR
"Failed to initialize the IGMP6 control socket (err %d).\n",
err);
- igmp6_socket = NULL; /* For safety. */
- return err;
+ goto out;
}
- sk = igmp6_socket->sk;
+ net->ipv6.igmp_sk = sk = sock->sk;
+ sk_change_net(sk, net);
sk->sk_allocation = GFP_ATOMIC;
sk->sk_prot->unhash(sk);
np->hop_limit = 1;
#ifdef CONFIG_PROC_FS
- proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops);
- proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops);
+ err = -ENOMEM;
+ if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops))
+ goto out_sock_create;
+ if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO,
+ &igmp6_mcf_seq_fops)) {
+ proc_net_remove(net, "igmp6");
+ goto out_sock_create;
+ }
#endif
- return 0;
+ err = 0;
+out:
+ return err;
+
+out_sock_create:
+ sk_release_kernel(net->ipv6.igmp_sk);
+ goto out;
}
-void igmp6_cleanup(void)
+static void igmp6_net_exit(struct net *net)
{
- sock_release(igmp6_socket);
- igmp6_socket = NULL; /* for safety */
-
+ sk_release_kernel(net->ipv6.igmp_sk);
#ifdef CONFIG_PROC_FS
- proc_net_remove(&init_net, "mcfilter6");
- proc_net_remove(&init_net, "igmp6");
+ proc_net_remove(net, "mcfilter6");
+ proc_net_remove(net, "igmp6");
#endif
}
+
+static struct pernet_operations igmp6_net_ops = {
+ .init = igmp6_net_init,
+ .exit = igmp6_net_exit,
+};
+
+int __init igmp6_init(void)
+{
+ return register_pernet_subsys(&igmp6_net_ops);
+}
+
+void igmp6_cleanup(void)
+{
+ unregister_pernet_subsys(&igmp6_net_ops);
+}
static int mip6_destopt_init_state(struct xfrm_state *x)
{
if (x->id.spi) {
- printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
+ printk(KERN_INFO "%s: spi is not 0: %u\n", __func__,
x->id.spi);
return -EINVAL;
}
if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
printk(KERN_INFO "%s: state's mode is not %u: %u\n",
- __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
+ __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
return -EINVAL;
}
static int mip6_rthdr_init_state(struct xfrm_state *x)
{
if (x->id.spi) {
- printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
+ printk(KERN_INFO "%s: spi is not 0: %u\n", __func__,
x->id.spi);
return -EINVAL;
}
if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
printk(KERN_INFO "%s: state's mode is not %u: %u\n",
- __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
+ __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
return -EINVAL;
}
printk(KERN_INFO "Mobile IPv6\n");
if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
- printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __FUNCTION__);
+ printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __func__);
goto mip6_destopt_xfrm_fail;
}
if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
- printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__);
+ printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __func__);
goto mip6_rthdr_xfrm_fail;
}
if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
- printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __FUNCTION__);
+ printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __func__);
goto mip6_rawv6_mh_fail;
}
static void __exit mip6_fini(void)
{
if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
- printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __FUNCTION__);
+ printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __func__);
if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
- printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__);
+ printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __func__);
if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
- printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__);
+ printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __func__);
}
module_init(mip6_init);
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
-static struct socket *ndisc_socket;
-
static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
static int ndisc_constructor(struct neighbour *neigh);
static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
ND_PRINTK2(KERN_WARNING
"%s(): duplicated ND6 option found: type=%d\n",
- __FUNCTION__,
+ __func__,
nd_opt->nd_opt_type);
} else {
ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
*/
ND_PRINTK2(KERN_NOTICE
"%s(): ignored unsupported option; type=%d, len=%d\n",
- __FUNCTION__,
+ __func__,
nd_opt->nd_opt_type, nd_opt->nd_opt_len);
}
}
/*
* Send a Neighbour Advertisement
*/
-
-static inline void ndisc_flow_init(struct flowi *fl, u8 type,
- struct in6_addr *saddr, struct in6_addr *daddr,
- int oif)
-{
- memset(fl, 0, sizeof(*fl));
- ipv6_addr_copy(&fl->fl6_src, saddr);
- ipv6_addr_copy(&fl->fl6_dst, daddr);
- fl->proto = IPPROTO_ICMPV6;
- fl->fl_icmp_type = type;
- fl->fl_icmp_code = 0;
- fl->oif = oif;
- security_sk_classify_flow(ndisc_socket->sk, fl);
-}
-
static void __ndisc_send(struct net_device *dev,
struct neighbour *neigh,
struct in6_addr *daddr, struct in6_addr *saddr,
{
struct flowi fl;
struct dst_entry *dst;
- struct sock *sk = ndisc_socket->sk;
+ struct net *net = dev->nd_net;
+ struct sock *sk = net->ipv6.ndisc_sk;
struct sk_buff *skb;
struct icmp6hdr *hdr;
struct inet6_dev *idev;
type = icmp6h->icmp6_type;
- ndisc_flow_init(&fl, type, saddr, daddr,
- dev->ifindex);
+ icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex);
- dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
+ dst = icmp6_dst_alloc(dev, neigh, daddr);
if (!dst)
return;
if (!skb) {
ND_PRINTK0(KERN_ERR
"ICMPv6 ND: %s() failed to allocate an skb.\n",
- __FUNCTION__);
+ __func__);
dst_release(dst);
return;
}
};
/* for anycast or proxy, solicited_addr != src_addr */
- ifp = ipv6_get_ifaddr(&init_net, solicited_addr, dev, 1);
+ ifp = ipv6_get_ifaddr(dev->nd_net, solicited_addr, dev, 1);
if (ifp) {
src_addr = solicited_addr;
if (ifp->flags & IFA_F_OPTIMISTIC)
* suppress the inclusion of the sllao.
*/
if (send_sllao) {
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(&init_net, saddr,
+ struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev->nd_net, saddr,
dev, 1);
if (ifp) {
if (ifp->flags & IFA_F_OPTIMISTIC) {
struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
int probes = atomic_read(&neigh->probes);
- if (skb && ipv6_chk_addr(&init_net, &ipv6_hdr(skb)->saddr, dev, 1))
+ if (skb && ipv6_chk_addr(dev->nd_net, &ipv6_hdr(skb)->saddr, dev, 1))
saddr = &ipv6_hdr(skb)->saddr;
if ((probes -= neigh->parms->ucast_probes) < 0) {
ND_PRINTK1(KERN_DEBUG
"%s(): trying to ucast probe in NUD_INVALID: "
NIP6_FMT "\n",
- __FUNCTION__,
+ __func__,
NIP6(*target));
}
ndisc_send_ns(dev, neigh, target, target, saddr);
inc = ipv6_addr_is_multicast(daddr);
- if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1)) != NULL) {
+ ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1);
+ if (ifp) {
if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
if (dad) {
if (ipv6_chk_acast_addr(dev, &msg->target) ||
(idev->cnf.forwarding &&
(ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) &&
- (pneigh = pneigh_lookup(&nd_tbl, &init_net,
+ (pneigh = pneigh_lookup(&nd_tbl, dev->nd_net,
&msg->target, dev, 0)) != NULL)) {
if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
skb->pkt_type != PACKET_HOST &&
return;
}
}
- if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1))) {
+ ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1);
+ if (ifp) {
if (ifp->flags & IFA_F_TENTATIVE) {
addrconf_dad_failure(ifp);
return;
*/
if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
- pneigh_lookup(&nd_tbl, &init_net, &msg->target, dev, 0)) {
+ pneigh_lookup(&nd_tbl, dev->nd_net, &msg->target, dev, 0)) {
/* XXX: idev->cnf.prixy_ndp */
goto out;
}
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct nduseroptmsg *ndmsg;
+ struct net *net = ra->dev->nd_net;
int err;
int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
+ (opt->nd_opt_len << 3));
&ipv6_hdr(ra)->saddr);
nlmsg_end(skb, nlh);
- err = rtnl_notify(skb, &init_net, 0, RTNLGRP_ND_USEROPT, NULL,
+ err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL,
GFP_ATOMIC);
if (err < 0)
goto errout;
nlmsg_free(skb);
err = -EMSGSIZE;
errout:
- rtnl_set_sk_err(&init_net, RTNLGRP_ND_USEROPT, err);
+ rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
}
static void ndisc_router_discovery(struct sk_buff *skb)
if (rt == NULL) {
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: %s() failed to add default route.\n",
- __FUNCTION__);
+ __func__);
in6_dev_put(in6_dev);
return;
}
if (neigh == NULL) {
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: %s() got default router without neighbour.\n",
- __FUNCTION__);
+ __func__);
dst_release(&rt->u.dst);
in6_dev_put(in6_dev);
return;
void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
struct in6_addr *target)
{
- struct sock *sk = ndisc_socket->sk;
+ struct net_device *dev = skb->dev;
+ struct net *net = dev->nd_net;
+ struct sock *sk = net->ipv6.ndisc_sk;
int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
struct sk_buff *buff;
struct icmp6hdr *icmph;
struct in6_addr saddr_buf;
struct in6_addr *addrp;
- struct net_device *dev;
struct rt6_info *rt;
struct dst_entry *dst;
struct inet6_dev *idev;
int hlen;
u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
- dev = skb->dev;
-
if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
ND_PRINTK2(KERN_WARNING
"ICMPv6 Redirect: no link-local address on %s\n",
return;
}
- ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr,
- dev->ifindex);
+ icmpv6_flow_init(sk, &fl, NDISC_REDIRECT,
+ &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
- dst = ip6_route_output(NULL, &fl);
+ dst = ip6_route_output(net, NULL, &fl);
if (dst == NULL)
return;
if (buff == NULL) {
ND_PRINTK0(KERN_ERR
"ICMPv6 Redirect: %s() failed to allocate an skb.\n",
- __FUNCTION__);
+ __func__);
dst_release(dst);
return;
}
static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
-
- if (dev->nd_net != &init_net)
- return NOTIFY_DONE;
+ struct net *net = dev->nd_net;
switch (event) {
case NETDEV_CHANGEADDR:
neigh_changeaddr(&nd_tbl, dev);
- fib6_run_gc(~0UL);
+ fib6_run_gc(~0UL, net);
break;
case NETDEV_DOWN:
neigh_ifdown(&nd_tbl, dev);
- fib6_run_gc(~0UL);
+ fib6_run_gc(~0UL, net);
break;
default:
break;
#endif
-int __init ndisc_init(struct net_proto_family *ops)
+static int ndisc_net_init(struct net *net)
{
+ struct socket *sock;
struct ipv6_pinfo *np;
struct sock *sk;
int err;
- err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket);
+ err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock);
if (err < 0) {
ND_PRINTK0(KERN_ERR
"ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n",
err);
- ndisc_socket = NULL; /* For safety. */
return err;
}
- sk = ndisc_socket->sk;
+ net->ipv6.ndisc_sk = sk = sock->sk;
+ sk_change_net(sk, net);
+
np = inet6_sk(sk);
sk->sk_allocation = GFP_ATOMIC;
np->hop_limit = 255;
np->mc_loop = 0;
sk->sk_prot->unhash(sk);
+ return 0;
+}
+
+static void ndisc_net_exit(struct net *net)
+{
+ sk_release_kernel(net->ipv6.ndisc_sk);
+}
+
+static struct pernet_operations ndisc_net_ops = {
+ .init = ndisc_net_init,
+ .exit = ndisc_net_exit,
+};
+
+int __init ndisc_init(void)
+{
+ int err;
+
+ err = register_pernet_subsys(&ndisc_net_ops);
+ if (err)
+ return err;
/*
* Initialize the neighbour table
*/
-
neigh_table_init(&nd_tbl);
#ifdef CONFIG_SYSCTL
- neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH,
- "ipv6",
- &ndisc_ifinfo_sysctl_change,
- &ndisc_ifinfo_sysctl_strategy);
+ err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6,
+ NET_IPV6_NEIGH, "ipv6",
+ &ndisc_ifinfo_sysctl_change,
+ &ndisc_ifinfo_sysctl_strategy);
+ if (err)
+ goto out_unregister_pernet;
#endif
+ err = register_netdevice_notifier(&ndisc_netdev_notifier);
+ if (err)
+ goto out_unregister_sysctl;
+out:
+ return err;
- register_netdevice_notifier(&ndisc_netdev_notifier);
- return 0;
+out_unregister_sysctl:
+#ifdef CONFIG_SYSCTL
+ neigh_sysctl_unregister(&nd_tbl.parms);
+out_unregister_pernet:
+#endif
+ unregister_pernet_subsys(&ndisc_net_ops);
+ goto out;
}
void ndisc_cleanup(void)
neigh_sysctl_unregister(&nd_tbl.parms);
#endif
neigh_table_clear(&nd_tbl);
- sock_release(ndisc_socket);
- ndisc_socket = NULL; /* For safety. */
+ unregister_pernet_subsys(&ndisc_net_ops);
}
.saddr = iph->saddr, } },
};
- dst = ip6_route_output(skb->sk, &fl);
+ dst = ip6_route_output(&init_net, skb->sk, &fl);
#ifdef CONFIG_XFRM
if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
static int nf_ip6_route(struct dst_entry **dst, struct flowi *fl)
{
- *dst = ip6_route_output(NULL, fl);
+ *dst = ip6_route_output(&init_net, NULL, fl);
return (*dst)->error;
}
do { \
if (!(x)) \
printk("IP_NF_ASSERT: %s:%s:%u\n", \
- __FUNCTION__, __FILE__, __LINE__); \
+ __func__, __FILE__, __LINE__); \
} while(0)
#else
#define IP_NF_ASSERT(x)
fl.fl_ip_sport = otcph.dest;
fl.fl_ip_dport = otcph.source;
security_skb_classify_flow(oldskb, &fl);
- dst = ip6_route_output(NULL, &fl);
+ dst = ip6_route_output(&init_net, NULL, &fl);
if (dst == NULL)
return;
if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0))
{
const struct ip6t_reject_info *reject = targinfo;
- pr_debug("%s: medium point\n", __FUNCTION__);
+ pr_debug("%s: medium point\n", __func__);
/* WARNING: This code causes reentry within ip6tables.
This means that the ip6tables jump stack is now crap. We
must return an absolute verdict. --RR */
if (!idev || !idev->dev)
return -EINVAL;
+ if (idev->dev->nd_net != &init_net)
+ return 0;
+
if (!proc_net_devsnmp6)
return -ENOENT;
#include <linux/if_arp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/nsproxy.h>
#include <net/net_namespace.h>
#include <net/snmp.h>
#include <net/ipv6.h>
static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
#ifdef CONFIG_IPV6_ROUTE_INFO
-static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
+static struct rt6_info *rt6_add_route_info(struct net *net,
+ struct in6_addr *prefix, int prefixlen,
struct in6_addr *gwaddr, int ifindex,
unsigned pref);
-static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
+static struct rt6_info *rt6_get_route_info(struct net *net,
+ struct in6_addr *prefix, int prefixlen,
struct in6_addr *gwaddr, int ifindex);
#endif
-static struct dst_ops ip6_dst_ops = {
+static struct dst_ops ip6_dst_ops_template = {
.family = AF_INET6,
.protocol = __constant_htons(ETH_P_IPV6),
.gc = ip6_dst_gc,
.entries = ATOMIC_INIT(0),
};
-struct rt6_info ip6_null_entry = {
+static struct rt6_info ip6_null_entry_template = {
.u = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
.input = ip6_pkt_discard,
.output = ip6_pkt_discard_out,
- .ops = &ip6_dst_ops,
- .path = (struct dst_entry*)&ip6_null_entry,
}
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct sk_buff *skb);
-struct rt6_info ip6_prohibit_entry = {
+struct rt6_info ip6_prohibit_entry_template = {
.u = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
.input = ip6_pkt_prohibit,
.output = ip6_pkt_prohibit_out,
- .ops = &ip6_dst_ops,
- .path = (struct dst_entry*)&ip6_prohibit_entry,
}
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_ref = ATOMIC_INIT(1),
};
-struct rt6_info ip6_blk_hole_entry = {
+static struct rt6_info ip6_blk_hole_entry_template = {
.u = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
.input = dst_discard,
.output = dst_discard,
- .ops = &ip6_dst_ops,
- .path = (struct dst_entry*)&ip6_blk_hole_entry,
}
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
#endif
/* allocate dst with ip6_dst_ops */
-static __inline__ struct rt6_info *ip6_dst_alloc(void)
+static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops)
{
- return (struct rt6_info *)dst_alloc(&ip6_dst_ops);
+ return (struct rt6_info *)dst_alloc(ops);
}
static void ip6_dst_destroy(struct dst_entry *dst)
* Route lookup. Any table->tb6_lock is implied.
*/
-static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
+static inline struct rt6_info *rt6_device_match(struct net *net,
+ struct rt6_info *rt,
int oif,
int strict)
{
return local;
if (strict)
- return &ip6_null_entry;
+ return net->ipv6.ip6_null_entry;
}
return rt;
}
static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
{
struct rt6_info *match, *rt0;
+ struct net *net;
RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
- __FUNCTION__, fn->leaf, oif);
+ __func__, fn->leaf, oif);
rt0 = fn->rr_ptr;
if (!rt0)
}
RT6_TRACE("%s() => %p\n",
- __FUNCTION__, match);
+ __func__, match);
- return (match ? match : &ip6_null_entry);
+ net = rt0->rt6i_dev->nd_net;
+ return (match ? match : net->ipv6.ip6_null_entry);
}
#ifdef CONFIG_IPV6_ROUTE_INFO
int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
struct in6_addr *gwaddr)
{
+ struct net *net = dev->nd_net;
struct route_info *rinfo = (struct route_info *) opt;
struct in6_addr prefix_buf, *prefix;
unsigned int pref;
prefix = &prefix_buf;
}
- rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex);
+ rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
+ dev->ifindex);
if (rt && !lifetime) {
ip6_del_rt(rt);
}
if (!rt && lifetime)
- rt = rt6_add_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
+ rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
pref);
else if (rt)
rt->rt6i_flags = RTF_ROUTEINFO |
}
#endif
-#define BACKTRACK(saddr) \
+#define BACKTRACK(__net, saddr) \
do { \
- if (rt == &ip6_null_entry) { \
+ if (rt == __net->ipv6.ip6_null_entry) { \
struct fib6_node *pn; \
while (1) { \
if (fn->fn_flags & RTN_TL_ROOT) \
} \
} while(0)
-static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
+static struct rt6_info *ip6_pol_route_lookup(struct net *net,
+ struct fib6_table *table,
struct flowi *fl, int flags)
{
struct fib6_node *fn;
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart:
rt = fn->leaf;
- rt = rt6_device_match(rt, fl->oif, flags);
- BACKTRACK(&fl->fl6_src);
+ rt = rt6_device_match(net, rt, fl->oif, flags);
+ BACKTRACK(net, &fl->fl6_src);
out:
dst_use(&rt->u.dst, jiffies);
read_unlock_bh(&table->tb6_lock);
}
-struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
- int oif, int strict)
+struct rt6_info *rt6_lookup(struct net *net, struct in6_addr *daddr,
+ struct in6_addr *saddr, int oif, int strict)
{
struct flowi fl = {
.oif = oif,
flags |= RT6_LOOKUP_F_HAS_SADDR;
}
- dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
+ dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_lookup);
if (dst->error == 0)
return (struct rt6_info *) dst;
int ip6_ins_rt(struct rt6_info *rt)
{
struct nl_info info = {
- .nl_net = &init_net,
+ .nl_net = rt->rt6i_dev->nd_net,
};
return __ip6_ins_rt(rt, &info);
}
return rt;
}
-static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif,
- struct flowi *fl, int flags)
+static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
+ struct flowi *fl, int flags)
{
struct fib6_node *fn;
struct rt6_info *rt, *nrt;
restart:
rt = rt6_select(fn, oif, strict | reachable);
- BACKTRACK(&fl->fl6_src);
- if (rt == &ip6_null_entry ||
+
+ BACKTRACK(net, &fl->fl6_src);
+ if (rt == net->ipv6.ip6_null_entry ||
rt->rt6i_flags & RTF_CACHE)
goto out;
}
dst_release(&rt->u.dst);
- rt = nrt ? : &ip6_null_entry;
+ rt = nrt ? : net->ipv6.ip6_null_entry;
dst_hold(&rt->u.dst);
if (nrt) {
return rt;
}
-static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,
+static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
struct flowi *fl, int flags)
{
- return ip6_pol_route(table, fl->iif, fl, flags);
+ return ip6_pol_route(net, table, fl->iif, fl, flags);
}
void ip6_route_input(struct sk_buff *skb)
{
struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct net *net = skb->dev->nd_net;
int flags = RT6_LOOKUP_F_HAS_SADDR;
struct flowi fl = {
.iif = skb->dev->ifindex,
if (rt6_need_strict(&iph->daddr))
flags |= RT6_LOOKUP_F_IFACE;
- skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
+ skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
}
-static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
+static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
struct flowi *fl, int flags)
{
- return ip6_pol_route(table, fl->oif, fl, flags);
+ return ip6_pol_route(net, table, fl->oif, fl, flags);
}
-struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
+struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
+ struct flowi *fl)
{
int flags = 0;
if (!ipv6_addr_any(&fl->fl6_src))
flags |= RT6_LOOKUP_F_HAS_SADDR;
- return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
+ return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output);
}
EXPORT_SYMBOL(ip6_route_output);
static int ipv6_get_mtu(struct net_device *dev);
-static inline unsigned int ipv6_advmss(unsigned int mtu)
+static inline unsigned int ipv6_advmss(struct net *net, unsigned int mtu)
{
mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
- if (mtu < init_net.ipv6.sysctl.ip6_rt_min_advmss)
- mtu = init_net.ipv6.sysctl.ip6_rt_min_advmss;
+ if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
+ mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
/*
* Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
return mtu;
}
-static struct dst_entry *ndisc_dst_gc_list;
-static DEFINE_SPINLOCK(ndisc_lock);
+static struct dst_entry *icmp6_dst_gc_list;
+static DEFINE_SPINLOCK(icmp6_dst_lock);
-struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
+struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
- struct in6_addr *addr,
- int (*output)(struct sk_buff *))
+ struct in6_addr *addr)
{
struct rt6_info *rt;
struct inet6_dev *idev = in6_dev_get(dev);
+ struct net *net = dev->nd_net;
if (unlikely(idev == NULL))
return NULL;
- rt = ip6_dst_alloc();
+ rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
if (unlikely(rt == NULL)) {
in6_dev_put(idev);
goto out;
atomic_set(&rt->u.dst.__refcnt, 1);
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
- rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
- rt->u.dst.output = output;
+ rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
+ rt->u.dst.output = ip6_output;
#if 0 /* there's no chance to use these for ndisc */
rt->u.dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST
rt->rt6i_dst.plen = 128;
#endif
- spin_lock_bh(&ndisc_lock);
- rt->u.dst.next = ndisc_dst_gc_list;
- ndisc_dst_gc_list = &rt->u.dst;
- spin_unlock_bh(&ndisc_lock);
+ spin_lock_bh(&icmp6_dst_lock);
+ rt->u.dst.next = icmp6_dst_gc_list;
+ icmp6_dst_gc_list = &rt->u.dst;
+ spin_unlock_bh(&icmp6_dst_lock);
- fib6_force_start_gc();
+ fib6_force_start_gc(net);
out:
return &rt->u.dst;
}
-int ndisc_dst_gc(int *more)
+int icmp6_dst_gc(int *more)
{
struct dst_entry *dst, *next, **pprev;
int freed;
next = NULL;
freed = 0;
- spin_lock_bh(&ndisc_lock);
- pprev = &ndisc_dst_gc_list;
+ spin_lock_bh(&icmp6_dst_lock);
+ pprev = &icmp6_dst_gc_list;
while ((dst = *pprev) != NULL) {
if (!atomic_read(&dst->__refcnt)) {
}
}
- spin_unlock_bh(&ndisc_lock);
+ spin_unlock_bh(&icmp6_dst_lock);
return freed;
}
static int ip6_dst_gc(struct dst_ops *ops)
{
- static unsigned expire = 30*HZ;
- static unsigned long last_gc;
unsigned long now = jiffies;
-
- if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) &&
- atomic_read(&ip6_dst_ops.entries) <= init_net.ipv6.sysctl.ip6_rt_max_size)
+ struct net *net = ops->dst_net;
+ int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
+ int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
+ int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
+ int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
+ unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
+
+ if (time_after(rt_last_gc + rt_min_interval, now) &&
+ atomic_read(&ops->entries) <= rt_max_size)
goto out;
- expire++;
- fib6_run_gc(expire);
- last_gc = now;
- if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh)
- expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1;
-
+ net->ipv6.ip6_rt_gc_expire++;
+ fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
+ net->ipv6.ip6_rt_last_gc = now;
+ if (atomic_read(&ops->entries) < ops->gc_thresh)
+ net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
out:
- expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity;
- return (atomic_read(&ip6_dst_ops.entries) > init_net.ipv6.sysctl.ip6_rt_max_size);
+ net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
+ return (atomic_read(&ops->entries) > rt_max_size);
}
/* Clean host part of a prefix. Not necessary in radix tree,
int ip6_route_add(struct fib6_config *cfg)
{
int err;
+ struct net *net = cfg->fc_nlinfo.nl_net;
struct rt6_info *rt = NULL;
struct net_device *dev = NULL;
struct inet6_dev *idev = NULL;
#endif
if (cfg->fc_ifindex) {
err = -ENODEV;
- dev = dev_get_by_index(&init_net, cfg->fc_ifindex);
+ dev = dev_get_by_index(net, cfg->fc_ifindex);
if (!dev)
goto out;
idev = in6_dev_get(dev);
if (cfg->fc_metric == 0)
cfg->fc_metric = IP6_RT_PRIO_USER;
- table = fib6_new_table(cfg->fc_table);
+ table = fib6_new_table(net, cfg->fc_table);
if (table == NULL) {
err = -ENOBUFS;
goto out;
}
- rt = ip6_dst_alloc();
+ rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
if (rt == NULL) {
err = -ENOMEM;
if ((cfg->fc_flags & RTF_REJECT) ||
(dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {
/* hold loopback dev/idev if we haven't done so. */
- if (dev != init_net.loopback_dev) {
+ if (dev != net->loopback_dev) {
if (dev) {
dev_put(dev);
in6_dev_put(idev);
}
- dev = init_net.loopback_dev;
+ dev = net->loopback_dev;
dev_hold(dev);
idev = in6_dev_get(dev);
if (!idev) {
if (!(gwa_type&IPV6_ADDR_UNICAST))
goto out;
- grt = rt6_lookup(gw_addr, NULL, cfg->fc_ifindex, 1);
+ grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
err = -EHOSTUNREACH;
if (grt == NULL)
if (!rt->u.dst.metrics[RTAX_MTU-1])
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
if (!rt->u.dst.metrics[RTAX_ADVMSS-1])
- rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
+ rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
rt->u.dst.dev = dev;
rt->rt6i_idev = idev;
rt->rt6i_table = table;
+
+ cfg->fc_nlinfo.nl_net = dev->nd_net;
+
return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
out:
{
int err;
struct fib6_table *table;
+ struct net *net = rt->rt6i_dev->nd_net;
- if (rt == &ip6_null_entry)
+ if (rt == net->ipv6.ip6_null_entry)
return -ENOENT;
table = rt->rt6i_table;
int ip6_del_rt(struct rt6_info *rt)
{
struct nl_info info = {
- .nl_net = &init_net,
+ .nl_net = rt->rt6i_dev->nd_net,
};
return __ip6_del_rt(rt, &info);
}
struct rt6_info *rt;
int err = -ESRCH;
- table = fib6_get_table(cfg->fc_table);
+ table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
if (table == NULL)
return err;
struct in6_addr gateway;
};
-static struct rt6_info *__ip6_route_redirect(struct fib6_table *table,
+static struct rt6_info *__ip6_route_redirect(struct net *net,
+ struct fib6_table *table,
struct flowi *fl,
int flags)
{
}
if (!rt)
- rt = &ip6_null_entry;
- BACKTRACK(&fl->fl6_src);
+ rt = net->ipv6.ip6_null_entry;
+ BACKTRACK(net, &fl->fl6_src);
out:
dst_hold(&rt->u.dst);
struct net_device *dev)
{
int flags = RT6_LOOKUP_F_HAS_SADDR;
+ struct net *net = dev->nd_net;
struct ip6rd_flowi rdfl = {
.fl = {
.oif = dev->ifindex,
if (rt6_need_strict(dest))
flags |= RT6_LOOKUP_F_IFACE;
- return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
+ return (struct rt6_info *)fib6_rule_lookup(net, (struct flowi *)&rdfl,
+ flags, __ip6_route_redirect);
}
void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
{
struct rt6_info *rt, *nrt = NULL;
struct netevent_redirect netevent;
+ struct net *net = neigh->dev->nd_net;
rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
- if (rt == &ip6_null_entry) {
+ if (rt == net->ipv6.ip6_null_entry) {
if (net_ratelimit())
printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
"for redirect target\n");
nrt->rt6i_nexthop = neigh_clone(neigh);
/* Reset pmtu, it may be better */
nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
- nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst));
+ nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(neigh->dev->nd_net,
+ dst_mtu(&nrt->u.dst));
if (ip6_ins_rt(nrt))
goto out;
struct net_device *dev, u32 pmtu)
{
struct rt6_info *rt, *nrt;
+ struct net *net = dev->nd_net;
int allfrag = 0;
- rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);
+ rt = rt6_lookup(net, daddr, saddr, dev->ifindex, 0);
if (rt == NULL)
return;
rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
if (allfrag)
rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
- dst_set_expires(&rt->u.dst, init_net.ipv6.sysctl.ip6_rt_mtu_expires);
+ dst_set_expires(&rt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
goto out;
}
* which is 10 mins. After 10 mins the decreased pmtu is expired
* and detecting PMTU increase will be automatically happened.
*/
- dst_set_expires(&nrt->u.dst, init_net.ipv6.sysctl.ip6_rt_mtu_expires);
+ dst_set_expires(&nrt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
ip6_ins_rt(nrt);
static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
{
- struct rt6_info *rt = ip6_dst_alloc();
+ struct net *net = ort->rt6i_dev->nd_net;
+ struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
if (rt) {
rt->u.dst.input = ort->u.dst.input;
}
#ifdef CONFIG_IPV6_ROUTE_INFO
-static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
+static struct rt6_info *rt6_get_route_info(struct net *net,
+ struct in6_addr *prefix, int prefixlen,
struct in6_addr *gwaddr, int ifindex)
{
struct fib6_node *fn;
struct rt6_info *rt = NULL;
struct fib6_table *table;
- table = fib6_get_table(RT6_TABLE_INFO);
+ table = fib6_get_table(net, RT6_TABLE_INFO);
if (table == NULL)
return NULL;
return rt;
}
-static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
+static struct rt6_info *rt6_add_route_info(struct net *net,
+ struct in6_addr *prefix, int prefixlen,
struct in6_addr *gwaddr, int ifindex,
unsigned pref)
{
.fc_dst_len = prefixlen,
.fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
RTF_UP | RTF_PREF(pref),
+ .fc_nlinfo.pid = 0,
+ .fc_nlinfo.nlh = NULL,
+ .fc_nlinfo.nl_net = net,
};
ipv6_addr_copy(&cfg.fc_dst, prefix);
ip6_route_add(&cfg);
- return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex);
+ return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
}
#endif
struct rt6_info *rt;
struct fib6_table *table;
- table = fib6_get_table(RT6_TABLE_DFLT);
+ table = fib6_get_table(dev->nd_net, RT6_TABLE_DFLT);
if (table == NULL)
return NULL;
.fc_ifindex = dev->ifindex,
.fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
+ .fc_nlinfo.pid = 0,
+ .fc_nlinfo.nlh = NULL,
+ .fc_nlinfo.nl_net = dev->nd_net,
};
ipv6_addr_copy(&cfg.fc_gateway, gwaddr);
return rt6_get_dflt_router(gwaddr, dev);
}
-void rt6_purge_dflt_routers(void)
+void rt6_purge_dflt_routers(struct net *net)
{
struct rt6_info *rt;
struct fib6_table *table;
/* NOTE: Keep consistent with rt6_get_dflt_router */
- table = fib6_get_table(RT6_TABLE_DFLT);
+ table = fib6_get_table(net, RT6_TABLE_DFLT);
if (table == NULL)
return;
read_unlock_bh(&table->tb6_lock);
}
-static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg,
+static void rtmsg_to_fib6_config(struct net *net,
+ struct in6_rtmsg *rtmsg,
struct fib6_config *cfg)
{
memset(cfg, 0, sizeof(*cfg));
cfg->fc_src_len = rtmsg->rtmsg_src_len;
cfg->fc_flags = rtmsg->rtmsg_flags;
- cfg->fc_nlinfo.nl_net = &init_net;
+ cfg->fc_nlinfo.nl_net = net;
ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst);
ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src);
ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway);
}
-int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
+int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct fib6_config cfg;
struct in6_rtmsg rtmsg;
if (err)
return -EFAULT;
- rtmsg_to_fib6_config(&rtmsg, &cfg);
+ rtmsg_to_fib6_config(net, &rtmsg, &cfg);
rtnl_lock();
switch (cmd) {
const struct in6_addr *addr,
int anycast)
{
- struct rt6_info *rt = ip6_dst_alloc();
+ struct net *net = idev->dev->nd_net;
+ struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
if (rt == NULL)
return ERR_PTR(-ENOMEM);
- dev_hold(init_net.loopback_dev);
+ dev_hold(net->loopback_dev);
in6_dev_hold(idev);
rt->u.dst.flags = DST_HOST;
rt->u.dst.input = ip6_input;
rt->u.dst.output = ip6_output;
- rt->rt6i_dev = init_net.loopback_dev;
+ rt->rt6i_dev = net->loopback_dev;
rt->rt6i_idev = idev;
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
- rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
+ rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
rt->u.dst.obsolete = -1;
ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
rt->rt6i_dst.plen = 128;
- rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL);
+ rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
atomic_set(&rt->u.dst.__refcnt, 1);
return rt;
}
+struct arg_dev_net {
+ struct net_device *dev;
+ struct net *net;
+};
+
static int fib6_ifdown(struct rt6_info *rt, void *arg)
{
- if (((void*)rt->rt6i_dev == arg || arg == NULL) &&
- rt != &ip6_null_entry) {
+ struct net_device *dev = ((struct arg_dev_net *)arg)->dev;
+ struct net *net = ((struct arg_dev_net *)arg)->net;
+
+ if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
+ rt != net->ipv6.ip6_null_entry) {
RT6_TRACE("deleted by ifdown %p\n", rt);
return -1;
}
return 0;
}
-void rt6_ifdown(struct net_device *dev)
+void rt6_ifdown(struct net *net, struct net_device *dev)
{
- fib6_clean_all(fib6_ifdown, 0, dev);
+ struct arg_dev_net adn = {
+ .dev = dev,
+ .net = net,
+ };
+
+ fib6_clean_all(net, fib6_ifdown, 0, &adn);
}
struct rt6_mtu_change_arg
{
struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
struct inet6_dev *idev;
+ struct net *net = arg->dev->nd_net;
/* In IPv6 pmtu discovery is not optional,
so that RTAX_MTU lock cannot disable it.
(dst_mtu(&rt->u.dst) < arg->mtu &&
dst_mtu(&rt->u.dst) == idev->cnf.mtu6))) {
rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
- rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(arg->mtu);
+ rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu);
}
return 0;
}
.mtu = mtu,
};
- fib6_clean_all(rt6_mtu_change_route, 0, &arg);
+ fib6_clean_all(dev->nd_net, rt6_mtu_change_route, 0, &arg);
}
static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
- struct net *net = skb->sk->sk_net;
struct fib6_config cfg;
int err;
- if (net != &init_net)
- return -EINVAL;
-
err = rtm_to_fib6_config(skb, nlh, &cfg);
if (err < 0)
return err;
static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
- struct net *net = skb->sk->sk_net;
struct fib6_config cfg;
int err;
- if (net != &init_net)
- return -EINVAL;
-
err = rtm_to_fib6_config(skb, nlh, &cfg);
if (err < 0)
return err;
NLA_PUT_U32(skb, RTA_IIF, iif);
else if (dst) {
struct in6_addr saddr_buf;
- if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0)
+ if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+ dst, &saddr_buf) == 0)
NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
}
struct flowi fl;
int err, iif = 0;
- if (net != &init_net)
- return -EINVAL;
-
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
if (err < 0)
goto errout;
if (iif) {
struct net_device *dev;
- dev = __dev_get_by_index(&init_net, iif);
+ dev = __dev_get_by_index(net, iif);
if (!dev) {
err = -ENODEV;
goto errout;
skb_reset_mac_header(skb);
skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
- rt = (struct rt6_info*) ip6_route_output(NULL, &fl);
+ rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
skb->dst = &rt->u.dst;
err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
goto errout;
}
- err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
+ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
errout:
return err;
}
void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
{
struct sk_buff *skb;
+ struct net *net = info->nl_net;
u32 seq;
int err;
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, &init_net, info->pid,
- RTNLGRP_IPV6_ROUTE, info->nlh, gfp_any());
+ err = rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
+ info->nlh, gfp_any());
errout:
if (err < 0)
- rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_ROUTE, err);
+ rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
+}
+
+static int ip6_route_dev_notify(struct notifier_block *this,
+ unsigned long event, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct net *net = dev->nd_net;
+
+ if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
+ net->ipv6.ip6_null_entry->u.dst.dev = dev;
+ net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ net->ipv6.ip6_prohibit_entry->u.dst.dev = dev;
+ net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
+ net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev;
+ net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
+#endif
+ }
+
+ return NOTIFY_OK;
}
/*
static int ipv6_route_show(struct seq_file *m, void *v)
{
- fib6_clean_all(rt6_info_route, 0, m);
+ struct net *net = (struct net *)m->private;
+ fib6_clean_all(net, rt6_info_route, 0, m);
return 0;
}
static int ipv6_route_open(struct inode *inode, struct file *file)
{
- return single_open(file, ipv6_route_show, NULL);
+ struct net *net = get_proc_net(inode);
+ if (!net)
+ return -ENXIO;
+ return single_open(file, ipv6_route_show, net);
+}
+
+static int ipv6_route_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct net *net = seq->private;
+ put_net(net);
+ return single_release(inode, file);
}
static const struct file_operations ipv6_route_proc_fops = {
.open = ipv6_route_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = single_release,
+ .release = ipv6_route_release,
};
static int rt6_stats_seq_show(struct seq_file *seq, void *v)
{
+ struct net *net = (struct net *)seq->private;
seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
- rt6_stats.fib_nodes, rt6_stats.fib_route_nodes,
- rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries,
- rt6_stats.fib_rt_cache,
- atomic_read(&ip6_dst_ops.entries),
- rt6_stats.fib_discarded_routes);
+ net->ipv6.rt6_stats->fib_nodes,
+ net->ipv6.rt6_stats->fib_route_nodes,
+ net->ipv6.rt6_stats->fib_rt_alloc,
+ net->ipv6.rt6_stats->fib_rt_entries,
+ net->ipv6.rt6_stats->fib_rt_cache,
+ atomic_read(&net->ipv6.ip6_dst_ops->entries),
+ net->ipv6.rt6_stats->fib_discarded_routes);
return 0;
}
static int rt6_stats_seq_open(struct inode *inode, struct file *file)
{
- return single_open(file, rt6_stats_seq_show, NULL);
+ struct net *net = get_proc_net(inode);
+ return single_open(file, rt6_stats_seq_show, net);
+}
+
+static int rt6_stats_seq_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct net *net = (struct net *)seq->private;
+ put_net(net);
+ return single_release(inode, file);
}
static const struct file_operations rt6_stats_seq_fops = {
.open = rt6_stats_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = single_release,
+ .release = rt6_stats_seq_release,
};
-
-static int ipv6_route_proc_init(struct net *net)
-{
- int ret = -ENOMEM;
- if (!proc_net_fops_create(net, "ipv6_route",
- 0, &ipv6_route_proc_fops))
- goto out;
-
- if (!proc_net_fops_create(net, "rt6_stats",
- S_IRUGO, &rt6_stats_seq_fops))
- goto out_ipv6_route;
-
- ret = 0;
-out:
- return ret;
-out_ipv6_route:
- proc_net_remove(net, "ipv6_route");
- goto out;
-}
-
-static void ipv6_route_proc_fini(struct net *net)
-{
- proc_net_remove(net, "ipv6_route");
- proc_net_remove(net, "rt6_stats");
-}
-#else
-static inline int ipv6_route_proc_init(struct net *net)
-{
- return 0;
-}
-static inline void ipv6_route_proc_fini(struct net *net)
-{
- return ;
-}
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_SYSCTL
int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
- int delay = init_net.ipv6.sysctl.flush_delay;
+ struct net *net = current->nsproxy->net_ns;
+ int delay = net->ipv6.sysctl.flush_delay;
if (write) {
proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
- fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay);
+ fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
return 0;
} else
return -EINVAL;
{
.ctl_name = NET_IPV6_ROUTE_GC_THRESH,
.procname = "gc_thresh",
- .data = &ip6_dst_ops.gc_thresh,
+ .data = &ip6_dst_ops_template.gc_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
table = kmemdup(ipv6_route_table_template,
sizeof(ipv6_route_table_template),
GFP_KERNEL);
+
+ if (table) {
+ table[0].data = &net->ipv6.sysctl.flush_delay;
+ table[1].data = &net->ipv6.ip6_dst_ops->gc_thresh;
+ table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
+ table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
+ table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
+ table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
+ table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
+ table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
+ table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
+ }
+
return table;
}
#endif
+static int ip6_route_net_init(struct net *net)
+{
+ int ret = 0;
+
+ ret = -ENOMEM;
+ net->ipv6.ip6_dst_ops = kmemdup(&ip6_dst_ops_template,
+ sizeof(*net->ipv6.ip6_dst_ops),
+ GFP_KERNEL);
+ if (!net->ipv6.ip6_dst_ops)
+ goto out;
+ net->ipv6.ip6_dst_ops->dst_net = net;
+
+ net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
+ sizeof(*net->ipv6.ip6_null_entry),
+ GFP_KERNEL);
+ if (!net->ipv6.ip6_null_entry)
+ goto out_ip6_dst_ops;
+ net->ipv6.ip6_null_entry->u.dst.path =
+ (struct dst_entry *)net->ipv6.ip6_null_entry;
+ net->ipv6.ip6_null_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
+
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
+ sizeof(*net->ipv6.ip6_prohibit_entry),
+ GFP_KERNEL);
+ if (!net->ipv6.ip6_prohibit_entry) {
+ kfree(net->ipv6.ip6_null_entry);
+ goto out;
+ }
+ net->ipv6.ip6_prohibit_entry->u.dst.path =
+ (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
+ net->ipv6.ip6_prohibit_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
+
+ net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
+ sizeof(*net->ipv6.ip6_blk_hole_entry),
+ GFP_KERNEL);
+ if (!net->ipv6.ip6_blk_hole_entry) {
+ kfree(net->ipv6.ip6_null_entry);
+ kfree(net->ipv6.ip6_prohibit_entry);
+ goto out;
+ }
+ net->ipv6.ip6_blk_hole_entry->u.dst.path =
+ (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
+ net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
+#endif
+
+#ifdef CONFIG_PROC_FS
+ proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
+ proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
+#endif
+ net->ipv6.ip6_rt_gc_expire = 30*HZ;
+
+ ret = 0;
+out:
+ return ret;
+
+out_ip6_dst_ops:
+ kfree(net->ipv6.ip6_dst_ops);
+ goto out;
+}
+
+static void ip6_route_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_remove(net, "ipv6_route");
+ proc_net_remove(net, "rt6_stats");
+#endif
+ kfree(net->ipv6.ip6_null_entry);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ kfree(net->ipv6.ip6_prohibit_entry);
+ kfree(net->ipv6.ip6_blk_hole_entry);
+#endif
+ kfree(net->ipv6.ip6_dst_ops);
+}
+
+static struct pernet_operations ip6_route_net_ops = {
+ .init = ip6_route_net_init,
+ .exit = ip6_route_net_exit,
+};
+
+static struct notifier_block ip6_route_dev_notifier = {
+ .notifier_call = ip6_route_dev_notify,
+ .priority = 0,
+};
+
int __init ip6_route_init(void)
{
int ret;
- ip6_dst_ops.kmem_cachep =
+ ret = -ENOMEM;
+ ip6_dst_ops_template.kmem_cachep =
kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
SLAB_HWCACHE_ALIGN, NULL);
- if (!ip6_dst_ops.kmem_cachep)
- return -ENOMEM;
+ if (!ip6_dst_ops_template.kmem_cachep)
+ goto out;;
- ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
-
- ret = fib6_init();
+ ret = register_pernet_subsys(&ip6_route_net_ops);
if (ret)
goto out_kmem_cache;
- ret = ipv6_route_proc_init(&init_net);
+ /* Registering of the loopback is done before this portion of code,
+ * the loopback reference in rt6_info will not be taken, do it
+ * manually for init_net */
+ init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev;
+ init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
+ init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
+ init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ #endif
+ ret = fib6_init();
if (ret)
- goto out_fib6_init;
+ goto out_register_subsys;
ret = xfrm6_init();
if (ret)
- goto out_proc_init;
+ goto out_fib6_init;
ret = fib6_rules_init();
if (ret)
__rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
goto fib6_rules_init;
- ret = 0;
+ ret = register_netdevice_notifier(&ip6_route_dev_notifier);
+ if (ret)
+ goto fib6_rules_init;
+
out:
return ret;
fib6_rules_cleanup();
xfrm6_init:
xfrm6_fini();
-out_proc_init:
- ipv6_route_proc_fini(&init_net);
out_fib6_init:
- rt6_ifdown(NULL);
fib6_gc_cleanup();
+out_register_subsys:
+ unregister_pernet_subsys(&ip6_route_net_ops);
out_kmem_cache:
- kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
+ kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
goto out;
}
void ip6_route_cleanup(void)
{
+ unregister_netdevice_notifier(&ip6_route_dev_notifier);
fib6_rules_cleanup();
- ipv6_route_proc_fini(&init_net);
xfrm6_fini();
- rt6_ifdown(NULL);
fib6_gc_cleanup();
- kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
+ unregister_pernet_subsys(&ip6_route_net_ops);
+ kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
}
skb_reset_network_header(skb2);
/* Try to guess incoming interface */
- rt6i = rt6_lookup(&iph6->saddr, NULL, NULL, 0);
+ rt6i = rt6_lookup(&init_net, &iph6->saddr, NULL, NULL, 0);
if (rt6i && rt6i->rt6i_dev) {
skb2->dev = rt6i->rt6i_dev;
- rt6i = rt6_lookup(&iph6->daddr, &iph6->saddr, NULL, 0);
+ rt6i = rt6_lookup(&init_net, &iph6->daddr, &iph6->saddr, NULL, 0);
if (rt6i && rt6i->rt6i_dev && rt6i->rt6i_dev->type == ARPHRD_SIT) {
struct ip_tunnel *t = netdev_priv(rt6i->rt6i_dev);
fl.oif = dev->ifindex;
security_skb_classify_flow(skb, &fl);
- dst = ip6_route_output(NULL, &fl);
+ dst = ip6_route_output(&init_net, NULL, &fl);
if (!dst->error && (dst->dev == dev) && (neigh = dst->neighbour)) {
addr6 = (struct in6_addr*)&neigh->primary_key;
--- /dev/null
+/*
+ * IPv6 Syncookies implementation for the Linux kernel
+ *
+ * Authors:
+ * Glenn Griffin <ggriffin.kernel@gmail.com>
+ *
+ * Based on IPv4 implementation by Andi Kleen
+ * linux/net/ipv4/syncookies.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.
+ *
+ */
+
+#include <linux/tcp.h>
+#include <linux/random.h>
+#include <linux/cryptohash.h>
+#include <linux/kernel.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+
+extern int sysctl_tcp_syncookies;
+extern __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
+
+#define COOKIEBITS 24 /* Upper bits store count */
+#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+
+/*
+ * This table has to be sorted and terminated with (__u16)-1.
+ * XXX generate a better table.
+ * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
+ *
+ * Taken directly from ipv4 implementation.
+ * Should this list be modified for ipv6 use or is it close enough?
+ * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart
+ */
+static __u16 const msstab[] = {
+ 64 - 1,
+ 256 - 1,
+ 512 - 1,
+ 536 - 1,
+ 1024 - 1,
+ 1440 - 1,
+ 1460 - 1,
+ 4312 - 1,
+ (__u16)-1
+};
+/* The number doesn't include the -1 terminator */
+#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
+
+/*
+ * This (misnamed) value is the age of syncookie which is permitted.
+ * Its ideal value should be dependent on TCP_TIMEOUT_INIT and
+ * sysctl_tcp_retries1. It's a rather complicated formula (exponential
+ * backoff) to compute at runtime so it's currently hardcoded here.
+ */
+#define COUNTER_TRIES 4
+
+static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req,
+ struct dst_entry *dst)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct sock *child;
+
+ child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst);
+ if (child)
+ inet_csk_reqsk_queue_add(sk, req, child);
+ else
+ reqsk_free(req);
+
+ return child;
+}
+
+static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+
+static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr,
+ __be16 sport, __be16 dport, u32 count, int c)
+{
+ __u32 *tmp = __get_cpu_var(cookie_scratch);
+
+ /*
+ * we have 320 bits of information to hash, copy in the remaining
+ * 192 bits required for sha_transform, from the syncookie_secret
+ * and overwrite the digest with the secret
+ */
+ memcpy(tmp + 10, syncookie_secret[c], 44);
+ memcpy(tmp, saddr, 16);
+ memcpy(tmp + 4, daddr, 16);
+ tmp[8] = ((__force u32)sport << 16) + (__force u32)dport;
+ tmp[9] = count;
+ sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
+
+ return tmp[17];
+}
+
+static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *daddr,
+ __be16 sport, __be16 dport, __u32 sseq,
+ __u32 count, __u32 data)
+{
+ return (cookie_hash(saddr, daddr, sport, dport, 0, 0) +
+ sseq + (count << COOKIEBITS) +
+ ((cookie_hash(saddr, daddr, sport, dport, count, 1) + data)
+ & COOKIEMASK));
+}
+
+static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr,
+ struct in6_addr *daddr, __be16 sport,
+ __be16 dport, __u32 sseq, __u32 count,
+ __u32 maxdiff)
+{
+ __u32 diff;
+
+ cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq;
+
+ diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS);
+ if (diff >= maxdiff)
+ return (__u32)-1;
+
+ return (cookie -
+ cookie_hash(saddr, daddr, sport, dport, count - diff, 1))
+ & COOKIEMASK;
+}
+
+__u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
+ int mssind;
+ const __u16 mss = *mssp;
+
+ tcp_sk(sk)->last_synq_overflow = jiffies;
+
+ for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
+ ;
+ *mssp = msstab[mssind] + 1;
+
+ NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESSENT);
+
+ return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source,
+ th->dest, ntohl(th->seq),
+ jiffies / (HZ * 60), mssind);
+}
+
+static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
+ __u32 seq = ntohl(th->seq) - 1;
+ __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr,
+ th->source, th->dest, seq,
+ jiffies / (HZ * 60), COUNTER_TRIES);
+
+ return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+}
+
+struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
+{
+ struct inet_request_sock *ireq;
+ struct inet6_request_sock *ireq6;
+ struct tcp_request_sock *treq;
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcphdr *th = tcp_hdr(skb);
+ __u32 cookie = ntohl(th->ack_seq) - 1;
+ struct sock *ret = sk;
+ struct request_sock *req;
+ int mss;
+ struct dst_entry *dst;
+ __u8 rcv_wscale;
+
+ if (!sysctl_tcp_syncookies || !th->ack)
+ goto out;
+
+ if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) ||
+ (mss = cookie_check(skb, cookie)) == 0) {
+ NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESFAILED);
+ goto out;
+ }
+
+ NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV);
+
+ ret = NULL;
+ req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
+ if (!req)
+ goto out;
+
+ ireq = inet_rsk(req);
+ ireq6 = inet6_rsk(req);
+ treq = tcp_rsk(req);
+ ireq6->pktopts = NULL;
+
+ if (security_inet_conn_request(sk, skb, req)) {
+ reqsk_free(req);
+ goto out;
+ }
+
+ req->mss = mss;
+ ireq->rmt_port = th->source;
+ ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);
+ ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);
+ if (ipv6_opt_accepted(sk, skb) ||
+ np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+ np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
+ atomic_inc(&skb->users);
+ ireq6->pktopts = skb;
+ }
+
+ ireq6->iif = sk->sk_bound_dev_if;
+ /* So that link locals have meaning */
+ if (!sk->sk_bound_dev_if &&
+ ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
+ ireq6->iif = inet6_iif(skb);
+
+ req->expires = 0UL;
+ req->retrans = 0;
+ ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0;
+ ireq->wscale_ok = ireq->sack_ok = 0;
+ treq->rcv_isn = ntohl(th->seq) - 1;
+ treq->snt_isn = cookie;
+
+ /*
+ * We need to lookup the dst_entry to get the correct window size.
+ * This is taken from tcp_v6_syn_recv_sock. Somebody please enlighten
+ * me if there is a preferred way.
+ */
+ {
+ struct in6_addr *final_p = NULL, final;
+ struct flowi fl;
+ memset(&fl, 0, sizeof(fl));
+ fl.proto = IPPROTO_TCP;
+ ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
+ if (np->opt && np->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+ ipv6_addr_copy(&final, &fl.fl6_dst);
+ ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+ final_p = &final;
+ }
+ ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_dport = inet_rsk(req)->rmt_port;
+ fl.fl_ip_sport = inet_sk(sk)->sport;
+ security_req_classify_flow(req, &fl);
+ if (ip6_dst_lookup(sk, &dst, &fl)) {
+ reqsk_free(req);
+ goto out;
+ }
+ if (final_p)
+ ipv6_addr_copy(&fl.fl6_dst, final_p);
+ if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+ goto out;
+ }
+
+ req->window_clamp = dst_metric(dst, RTAX_WINDOW);
+ tcp_select_initial_window(tcp_full_space(sk), req->mss,
+ &req->rcv_wnd, &req->window_clamp,
+ 0, &rcv_wscale);
+
+ ireq->rcv_wscale = rcv_wscale;
+
+ ret = get_cookie_sock(sk, skb, req, dst);
+
+out: return ret;
+}
+
ipv6_route_table = ipv6_route_sysctl_init(net);
if (!ipv6_route_table)
goto out_ipv6_table;
+ ipv6_table[0].child = ipv6_route_table;
ipv6_icmp_table = ipv6_icmp_sysctl_init(net);
if (!ipv6_icmp_table)
goto out_ipv6_route_table;
-
- ipv6_route_table[0].data = &net->ipv6.sysctl.flush_delay;
- /* ipv6_route_table[1].data will be handled when we have
- routes per namespace */
- ipv6_route_table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
- ipv6_route_table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
- ipv6_route_table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
- ipv6_route_table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
- ipv6_route_table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
- ipv6_route_table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
- ipv6_route_table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
- ipv6_table[0].child = ipv6_route_table;
-
- ipv6_icmp_table[0].data = &net->ipv6.sysctl.icmpv6_time;
ipv6_table[1].child = ipv6_icmp_table;
ipv6_table[2].data = &net->ipv6.sysctl.bindv6only;
#include <linux/crypto.h>
#include <linux/scatterlist.h>
-/* Socket used for sending RSTs and ACKs */
-static struct socket *tcp6_socket;
-
static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
static void tcp_v6_send_check(struct sock *sk, int len,
}
-static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
- struct dst_entry *dst)
+static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
{
struct inet6_request_sock *treq = inet6_rsk(req);
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6_txoptions *opt = NULL;
struct in6_addr * final_p = NULL, final;
struct flowi fl;
+ struct dst_entry *dst;
int err = -1;
memset(&fl, 0, sizeof(fl));
fl.fl_ip_sport = inet_sk(sk)->sport;
security_req_classify_flow(req, &fl);
- if (dst == NULL) {
- opt = np->opt;
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
-
- err = ip6_dst_lookup(sk, &dst, &fl);
- if (err)
- goto done;
- if (final_p)
- ipv6_addr_copy(&fl.fl6_dst, final_p);
- if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
- goto done;
+ opt = np->opt;
+ if (opt && opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+ ipv6_addr_copy(&final, &fl.fl6_dst);
+ ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+ final_p = &final;
}
+ err = ip6_dst_lookup(sk, &dst, &fl);
+ if (err)
+ goto done;
+ if (final_p)
+ ipv6_addr_copy(&fl.fl6_dst, final_p);
+ if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+ goto done;
+
skb = tcp_make_synack(sk, dst, req);
if (skb) {
struct tcphdr *th = tcp_hdr(skb);
return err;
}
+static inline void syn_flood_warning(struct sk_buff *skb)
+{
+#ifdef CONFIG_SYN_COOKIES
+ if (sysctl_tcp_syncookies)
+ printk(KERN_INFO
+ "TCPv6: Possible SYN flooding on port %d. "
+ "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
+ else
+#endif
+ printk(KERN_INFO
+ "TCPv6: Possible SYN flooding on port %d. "
+ "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
+}
+
static void tcp_v6_reqsk_destructor(struct request_sock *req)
{
if (inet6_rsk(req)->pktopts)
hp = tcp_get_md5sig_pool();
if (!hp) {
- printk(KERN_WARNING "%s(): hash pool not found...\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
goto clear_hash_noput;
}
bp = &hp->md5_blk.ip6;
/* Now store the hash into the packet */
err = crypto_hash_init(desc);
if (err) {
- printk(KERN_WARNING "%s(): hash_init failed\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
goto clear_hash;
}
err = crypto_hash_update(desc, sg, nbytes);
if (err) {
- printk(KERN_WARNING "%s(): hash_update failed\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
goto clear_hash;
}
err = crypto_hash_final(desc, md5_hash);
if (err) {
- printk(KERN_WARNING "%s(): hash_final failed\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
goto clear_hash;
}
}
#endif
-static struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
+struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
.family = AF_INET6,
.obj_size = sizeof(struct tcp6_request_sock),
.rtx_syn_ack = tcp_v6_send_synack,
struct tcphdr *th = tcp_hdr(skb), *t1;
struct sk_buff *buff;
struct flowi fl;
+ struct net *net = skb->dst->dev->nd_net;
+ struct sock *ctl_sk = net->ipv6.tcp_sk;
unsigned int tot_len = sizeof(*th);
#ifdef CONFIG_TCP_MD5SIG
struct tcp_md5sig_key *key;
fl.fl_ip_sport = t1->source;
security_skb_classify_flow(skb, &fl);
- /* sk = NULL, but it is safe for now. RST socket required. */
- if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+ /* Pass a socket to ip6_dst_lookup either it is for RST
+ * Underlying function will use this to retrieve the network
+ * namespace
+ */
+ if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
- ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
+ ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
return;
struct tcphdr *th = tcp_hdr(skb), *t1;
struct sk_buff *buff;
struct flowi fl;
+ struct net *net = skb->dev->nd_net;
+ struct sock *ctl_sk = net->ipv6.tcp_sk;
unsigned int tot_len = sizeof(struct tcphdr);
__be32 *topt;
#ifdef CONFIG_TCP_MD5SIG
fl.fl_ip_sport = t1->source;
security_skb_classify_flow(skb, &fl);
- if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+ if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
- ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
+ ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
return;
}
return NULL;
}
-#if 0 /*def CONFIG_SYN_COOKIES*/
+#ifdef CONFIG_SYN_COOKIES
if (!th->rst && !th->syn && th->ack)
- sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
+ sk = cookie_v6_check(sk, skb);
#endif
return sk;
}
struct tcp_sock *tp = tcp_sk(sk);
struct request_sock *req = NULL;
__u32 isn = TCP_SKB_CB(skb)->when;
+#ifdef CONFIG_SYN_COOKIES
+ int want_cookie = 0;
+#else
+#define want_cookie 0
+#endif
if (skb->protocol == htons(ETH_P_IP))
return tcp_v4_conn_request(sk, skb);
if (!ipv6_unicast_destination(skb))
goto drop;
- /*
- * There are no SYN attacks on IPv6, yet...
- */
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
if (net_ratelimit())
- printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
+ syn_flood_warning(skb);
+#ifdef CONFIG_SYN_COOKIES
+ if (sysctl_tcp_syncookies)
+ want_cookie = 1;
+ else
+#endif
goto drop;
}
tcp_parse_options(skb, &tmp_opt, 0);
+ if (want_cookie) {
+ tcp_clear_options(&tmp_opt);
+ tmp_opt.saw_tstamp = 0;
+ }
+
tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
tcp_openreq_init(req, &tmp_opt, skb);
treq = inet6_rsk(req);
ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
- TCP_ECN_create_request(req, tcp_hdr(skb));
treq->pktopts = NULL;
- if (ipv6_opt_accepted(sk, skb) ||
- np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
- np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
- atomic_inc(&skb->users);
- treq->pktopts = skb;
- }
- treq->iif = sk->sk_bound_dev_if;
+ if (!want_cookie)
+ TCP_ECN_create_request(req, tcp_hdr(skb));
+
+ if (want_cookie) {
+ isn = cookie_v6_init_sequence(sk, skb, &req->mss);
+ } else if (!isn) {
+ if (ipv6_opt_accepted(sk, skb) ||
+ np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+ np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
+ atomic_inc(&skb->users);
+ treq->pktopts = skb;
+ }
+ treq->iif = sk->sk_bound_dev_if;
- /* So that link locals have meaning */
- if (!sk->sk_bound_dev_if &&
- ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
- treq->iif = inet6_iif(skb);
+ /* So that link locals have meaning */
+ if (!sk->sk_bound_dev_if &&
+ ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
+ treq->iif = inet6_iif(skb);
- if (isn == 0)
isn = tcp_v6_init_sequence(skb);
+ }
tcp_rsk(req)->snt_isn = isn;
security_inet_conn_request(sk, skb, req);
- if (tcp_v6_send_synack(sk, req, NULL))
+ if (tcp_v6_send_synack(sk, req))
goto drop;
- inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
- return 0;
+ if (!want_cookie) {
+ inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
+ return 0;
+ }
drop:
if (req)
INET_PROTOSW_ICSK,
};
+static int tcpv6_net_init(struct net *net)
+{
+ int err;
+ struct socket *sock;
+ struct sock *sk;
+
+ err = inet_csk_ctl_sock_create(&sock, PF_INET6, SOCK_RAW, IPPROTO_TCP);
+ if (err)
+ return err;
+
+ net->ipv6.tcp_sk = sk = sock->sk;
+ sk_change_net(sk, net);
+ return err;
+}
+
+static void tcpv6_net_exit(struct net *net)
+{
+ sk_release_kernel(net->ipv6.tcp_sk);
+}
+
+static struct pernet_operations tcpv6_net_ops = {
+ .init = tcpv6_net_init,
+ .exit = tcpv6_net_exit,
+};
+
int __init tcpv6_init(void)
{
int ret;
if (ret)
goto out_tcpv6_protocol;
- ret = inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6,
- SOCK_RAW, IPPROTO_TCP);
+ ret = register_pernet_subsys(&tcpv6_net_ops);
if (ret)
goto out_tcpv6_protosw;
out:
void tcpv6_exit(void)
{
- sock_release(tcp6_socket);
+ unregister_pernet_subsys(&tcpv6_net_ops);
inet6_unregister_protosw(&tcpv6_protosw);
inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
}
sk_for_each_from(s, node) {
struct inet_sock *inet = inet_sk(s);
+ if (s->sk_net != sk->sk_net)
+ continue;
+
if (s->sk_hash == num && s->sk_family == PF_INET6) {
struct ipv6_pinfo *np = inet6_sk(s);
if (inet->dport) {
if (saddr)
memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src));
- dst = ip6_route_output(NULL, &fl);
+ dst = ip6_route_output(&init_net, NULL, &fl);
err = dst->error;
if (dst->error) {
if (IS_ERR(dst))
return -EHOSTUNREACH;
- ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6,
- (struct in6_addr *)&saddr->a6);
+ ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev,
+ (struct in6_addr *)&daddr->a6,
+ (struct in6_addr *)&saddr->a6);
dst_release(dst);
return 0;
}
struct sock *sk;
int err;
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
self = instance;
sk = instance;
err = sock_queue_rcv_skb(sk, skb);
if (err) {
- IRDA_DEBUG(1, "%s(), error: no more mem!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), error: no more mem!\n", __func__);
self->rx_flow = FLOW_STOP;
/* When we return error, TTP will need to requeue the skb */
self = instance;
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
/* Don't care about it, but let's not leak it */
if(skb)
sk = instance;
if (sk == NULL) {
IRDA_DEBUG(0, "%s(%p) : BUG : sk is NULL\n",
- __FUNCTION__, self);
+ __func__, self);
return;
}
self = instance;
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
sk = instance;
if (sk == NULL) {
case SOCK_STREAM:
if (max_sdu_size != 0) {
IRDA_ERROR("%s: max_sdu_size must be 0\n",
- __FUNCTION__);
+ __func__);
return;
}
self->max_data_size = irttp_get_max_seg_size(self->tsap);
case SOCK_SEQPACKET:
if (max_sdu_size == 0) {
IRDA_ERROR("%s: max_sdu_size cannot be 0\n",
- __FUNCTION__);
+ __func__);
return;
}
self->max_data_size = max_sdu_size;
self->max_data_size = irttp_get_max_seg_size(self->tsap);
}
- IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __func__,
self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
self = instance;
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
sk = instance;
if (sk == NULL) {
case SOCK_STREAM:
if (max_sdu_size != 0) {
IRDA_ERROR("%s: max_sdu_size must be 0\n",
- __FUNCTION__);
+ __func__);
kfree_skb(skb);
return;
}
case SOCK_SEQPACKET:
if (max_sdu_size == 0) {
IRDA_ERROR("%s: max_sdu_size cannot be 0\n",
- __FUNCTION__);
+ __func__);
kfree_skb(skb);
return;
}
self->max_data_size = irttp_get_max_seg_size(self->tsap);
}
- IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __func__,
self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
{
struct sk_buff *skb;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
GFP_ATOMIC);
if (skb == NULL) {
IRDA_DEBUG(0, "%s() Unable to allocate sk_buff!\n",
- __FUNCTION__);
+ __func__);
return;
}
struct irda_sock *self;
struct sock *sk;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
self = instance;
sk = instance;
switch (flow) {
case FLOW_STOP:
IRDA_DEBUG(1, "%s(), IrTTP wants us to slow down\n",
- __FUNCTION__);
+ __func__);
self->tx_flow = flow;
break;
case FLOW_START:
self->tx_flow = flow;
IRDA_DEBUG(1, "%s(), IrTTP wants us to start again\n",
- __FUNCTION__);
+ __func__);
wake_up_interruptible(sk->sk_sleep);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __func__);
/* Unknown flow command, better stop */
self->tx_flow = flow;
break;
self = (struct irda_sock *) priv;
if (!self) {
- IRDA_WARNING("%s: lost myself!\n", __FUNCTION__);
+ IRDA_WARNING("%s: lost myself!\n", __func__);
return;
}
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
/* We probably don't need to make any more queries */
iriap_close(self->iriap);
/* Check if request succeeded */
if (result != IAS_SUCCESS) {
- IRDA_DEBUG(1, "%s(), IAS query failed! (%d)\n", __FUNCTION__,
+ IRDA_DEBUG(1, "%s(), IAS query failed! (%d)\n", __func__,
result);
self->errno = result; /* We really need it later */
{
struct irda_sock *self;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
self = (struct irda_sock *) priv;
if (!self) {
- IRDA_WARNING("%s: lost myself!\n", __FUNCTION__);
+ IRDA_WARNING("%s: lost myself!\n", __func__);
return;
}
{
struct irda_sock *self;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
self = (struct irda_sock *) priv;
BUG_ON(self == NULL);
notify_t notify;
if (self->tsap) {
- IRDA_WARNING("%s: busy!\n", __FUNCTION__);
+ IRDA_WARNING("%s: busy!\n", __func__);
return -EBUSY;
}
¬ify);
if (self->tsap == NULL) {
IRDA_DEBUG(0, "%s(), Unable to allocate TSAP!\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
/* Remember which TSAP selector we actually got */
notify_t notify;
if (self->lsap) {
- IRDA_WARNING("%s(), busy!\n", __FUNCTION__);
+ IRDA_WARNING("%s(), busy!\n", __func__);
return -EBUSY;
}
self->lsap = irlmp_open_lsap(LSAP_CONNLESS, ¬ify, pid);
if (self->lsap == NULL) {
- IRDA_DEBUG( 0, "%s(), Unable to allocate LSAP!\n", __FUNCTION__);
+ IRDA_DEBUG( 0, "%s(), Unable to allocate LSAP!\n", __func__);
return -ENOMEM;
}
*/
static int irda_find_lsap_sel(struct irda_sock *self, char *name)
{
- IRDA_DEBUG(2, "%s(%p, %s)\n", __FUNCTION__, self, name);
+ IRDA_DEBUG(2, "%s(%p, %s)\n", __func__, self, name);
if (self->iriap) {
IRDA_WARNING("%s(): busy with a previous query\n",
- __FUNCTION__);
+ __func__);
return -EBUSY;
}
switch (self->ias_result->type) {
case IAS_INTEGER:
IRDA_DEBUG(4, "%s() int=%d\n",
- __FUNCTION__, self->ias_result->t.integer);
+ __func__, self->ias_result->t.integer);
if (self->ias_result->t.integer != -1)
self->dtsap_sel = self->ias_result->t.integer;
break;
default:
self->dtsap_sel = 0;
- IRDA_DEBUG(0, "%s(), bad type!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), bad type!\n", __func__);
break;
}
if (self->ias_result)
__u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */
__u8 dtsap_sel = 0x0; /* TSAP associated with it */
- IRDA_DEBUG(2, "%s(), name=%s\n", __FUNCTION__, name);
+ IRDA_DEBUG(2, "%s(), name=%s\n", __func__, name);
/* Ask lmp for the current discovery log
* Note : we have to use irlmp_get_discoveries(), as opposed
self->daddr = discoveries[i].daddr;
self->saddr = 0x0;
IRDA_DEBUG(1, "%s(), trying daddr = %08x\n",
- __FUNCTION__, self->daddr);
+ __func__, self->daddr);
/* Query remote LM-IAS for this service */
err = irda_find_lsap_sel(self, name);
/* We found the requested service */
if(daddr != DEV_ADDR_ANY) {
IRDA_DEBUG(1, "%s(), discovered service ''%s'' in two different devices !!!\n",
- __FUNCTION__, name);
+ __func__, name);
self->daddr = DEV_ADDR_ANY;
kfree(discoveries);
return(-ENOTUNIQ);
break;
default:
/* Something bad did happen :-( */
- IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __func__);
self->daddr = DEV_ADDR_ANY;
kfree(discoveries);
return(-EHOSTUNREACH);
/* Check out what we found */
if(daddr == DEV_ADDR_ANY) {
IRDA_DEBUG(1, "%s(), cannot discover service ''%s'' in any device !!!\n",
- __FUNCTION__, name);
+ __func__, name);
self->daddr = DEV_ADDR_ANY;
return(-EADDRNOTAVAIL);
}
self->dtsap_sel = dtsap_sel;
IRDA_DEBUG(1, "%s(), discovered requested service ''%s'' at address %08x\n",
- __FUNCTION__, name, self->daddr);
+ __func__, name, self->daddr);
return 0;
}
saddr.sir_addr = self->saddr;
}
- IRDA_DEBUG(1, "%s(), tsap_sel = %#x\n", __FUNCTION__, saddr.sir_lsap_sel);
- IRDA_DEBUG(1, "%s(), addr = %08x\n", __FUNCTION__, saddr.sir_addr);
+ IRDA_DEBUG(1, "%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel);
+ IRDA_DEBUG(1, "%s(), addr = %08x\n", __func__, saddr.sir_addr);
/* uaddr_len come to us uninitialised */
*uaddr_len = sizeof (struct sockaddr_irda);
{
struct sock *sk = sock->sk;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
(sk->sk_type != SOCK_DGRAM))
struct irda_sock *self = irda_sk(sk);
int err;
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
if (addr_len != sizeof(struct sockaddr_irda))
return -EINVAL;
(sk->sk_protocol == IRDAPROTO_ULTRA)) {
self->pid = addr->sir_lsap_sel;
if (self->pid & 0x80) {
- IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__);
return -EOPNOTSUPP;
}
err = irda_open_lsap(self, self->pid);
struct sk_buff *skb;
int err;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
err = irda_create(sk->sk_net, newsock, sk->sk_protocol);
if (err)
/* Now attach up the new socket */
new->tsap = irttp_dup(self->tsap, new);
if (!new->tsap) {
- IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
kfree_skb(skb);
return -1;
}
struct irda_sock *self = irda_sk(sk);
int err;
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
/* Don't allow connect for Ultra sockets */
if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA))
/* Try to find one suitable */
err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);
if (err) {
- IRDA_DEBUG(0, "%s(), auto-connect failed!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), auto-connect failed!\n", __func__);
return err;
}
} else {
/* Use the one provided by the user */
self->daddr = addr->sir_addr;
- IRDA_DEBUG(1, "%s(), daddr = %08x\n", __FUNCTION__, self->daddr);
+ IRDA_DEBUG(1, "%s(), daddr = %08x\n", __func__, self->daddr);
/* If we don't have a valid service name, we assume the
* user want to connect on a specific LSAP. Prevent
/* Query remote LM-IAS using service name */
err = irda_find_lsap_sel(self, addr->sir_name);
if (err) {
- IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
return err;
}
} else {
self->saddr, self->daddr, NULL,
self->max_sdu_size_rx, NULL);
if (err) {
- IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
return err;
}
struct sock *sk;
struct irda_sock *self;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
if (net != &init_net)
return -EAFNOSUPPORT;
return -ENOMEM;
self = irda_sk(sk);
- IRDA_DEBUG(2, "%s() : self is %p\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s() : self is %p\n", __func__, self);
init_waitqueue_head(&self->query_wait);
*/
static void irda_destroy_socket(struct irda_sock *self)
{
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
/* Unregister with IrLMP */
irlmp_unregister_client(self->ckey);
{
struct sock *sk = sock->sk;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
if (sk == NULL)
return 0;
struct sk_buff *skb;
int err = -EPIPE;
- IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
+ IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
/* Note : socket.c set MSG_EOR on SEQPACKET sockets */
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
/* Check that we don't send out too big frames */
if (len > self->max_data_size) {
IRDA_DEBUG(2, "%s(), Chopping frame from %zd to %d bytes!\n",
- __FUNCTION__, len, self->max_data_size);
+ __func__, len, self->max_data_size);
len = self->max_data_size;
}
*/
err = irttp_data_request(self->tsap, skb);
if (err) {
- IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);
+ IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
goto out_err;
}
/* Tell client how much data we actually sent */
size_t copied;
int err;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
if ((err = sock_error(sk)) < 0)
return err;
if (copied > size) {
IRDA_DEBUG(2, "%s(), Received truncated frame (%zd < %zd)!\n",
- __FUNCTION__, copied, size);
+ __func__, copied, size);
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
*/
if (self->rx_flow == FLOW_STOP) {
if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
- IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __func__);
self->rx_flow = FLOW_START;
irttp_flow_request(self->tsap, FLOW_START);
}
int target, err;
long timeo;
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
if ((err = sock_error(sk)) < 0)
return err;
/* put the skb back if we didn't use it up.. */
if (skb->len) {
IRDA_DEBUG(1, "%s(), back on q!\n",
- __FUNCTION__);
+ __func__);
skb_queue_head(&sk->sk_receive_queue, skb);
break;
}
kfree_skb(skb);
} else {
- IRDA_DEBUG(0, "%s() questionable!?\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() questionable!?\n", __func__);
/* put message back and return */
skb_queue_head(&sk->sk_receive_queue, skb);
*/
if (self->rx_flow == FLOW_STOP) {
if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
- IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __func__);
self->rx_flow = FLOW_START;
irttp_flow_request(self->tsap, FLOW_START);
}
struct sk_buff *skb;
int err;
- IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
+ IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
return -EINVAL;
if (len > self->max_data_size) {
IRDA_DEBUG(0, "%s(), Warning to much data! "
"Chopping frame from %zd to %d bytes!\n",
- __FUNCTION__, len, self->max_data_size);
+ __func__, len, self->max_data_size);
len = self->max_data_size;
}
skb_reserve(skb, self->max_header_size);
skb_reset_transport_header(skb);
- IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), appending user data\n", __func__);
skb_put(skb, len);
err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
if (err) {
*/
err = irttp_udata_request(self->tsap, skb);
if (err) {
- IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);
+ IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
return err;
}
return len;
struct sk_buff *skb;
int err;
- IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
+ IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
return -EINVAL;
pid = addr->sir_lsap_sel;
if (pid & 0x80) {
- IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__);
return -EOPNOTSUPP;
}
} else {
if ((self->lsap == NULL) ||
(sk->sk_state != TCP_ESTABLISHED)) {
IRDA_DEBUG(0, "%s(), socket not bound to Ultra PID.\n",
- __FUNCTION__);
+ __func__);
return -ENOTCONN;
}
/* Use PID from socket */
if (len > self->max_data_size) {
IRDA_DEBUG(0, "%s(), Warning to much data! "
"Chopping frame from %zd to %d bytes!\n",
- __FUNCTION__, len, self->max_data_size);
+ __func__, len, self->max_data_size);
len = self->max_data_size;
}
skb_reserve(skb, self->max_header_size);
skb_reset_transport_header(skb);
- IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), appending user data\n", __func__);
skb_put(skb, len);
err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
if (err) {
err = irlmp_connless_data_request((bound ? self->lsap : NULL),
skb, pid);
if (err) {
- IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);
+ IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
return err;
}
return len;
struct sock *sk = sock->sk;
struct irda_sock *self = irda_sk(sk);
- IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(1, "%s(%p)\n", __func__, self);
sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN;
struct irda_sock *self = irda_sk(sk);
unsigned int mask;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
poll_wait(file, sk->sk_sleep, wait);
mask = 0;
if (sk->sk_err)
mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN) {
- IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), POLLHUP\n", __func__);
mask |= POLLHUP;
}
switch (sk->sk_type) {
case SOCK_STREAM:
if (sk->sk_state == TCP_CLOSE) {
- IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), POLLHUP\n", __func__);
mask |= POLLHUP;
}
{
struct sock *sk = sock->sk;
- IRDA_DEBUG(4, "%s(), cmd=%#x\n", __FUNCTION__, cmd);
+ IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd);
switch (cmd) {
case TIOCOUTQ: {
case SIOCSIFMETRIC:
return -EINVAL;
default:
- IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__);
return -ENOIOCTLCMD;
}
struct ias_attrib * ias_attr; /* Attribute in IAS object */
int opt, free_ias = 0;
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
if (level != SOL_IRLMP)
return -ENOPROTOOPT;
/* Check is the user space own the object */
if(ias_attr->value->owner != IAS_USER_ATTR) {
- IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __func__);
kfree(ias_opt);
return -EPERM;
}
/* Only possible for a seqpacket service (TTP with SAR) */
if (sk->sk_type != SOCK_SEQPACKET) {
IRDA_DEBUG(2, "%s(), setting max_sdu_size = %d\n",
- __FUNCTION__, opt);
+ __func__, opt);
self->max_sdu_size_rx = opt;
} else {
IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
- __FUNCTION__);
+ __func__);
return -ENOPROTOOPT;
}
break;
int err;
int offset, total;
- IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
if (level != SOL_IRLMP)
return -ENOPROTOOPT;
/* Check that we can proceed with IAP */
if (self->iriap) {
IRDA_WARNING("%s: busy with a previous query\n",
- __FUNCTION__);
+ __func__);
kfree(ias_opt);
return -EBUSY;
}
if (!self->cachedaddr) {
int ret = 0;
- IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __func__);
/* Set watchdog timer to expire in <val> ms. */
self->errno = 0;
if(timer_pending(&(self->watchdog)))
del_timer(&(self->watchdog));
- IRDA_DEBUG(1, "%s(), ...waking up !\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), ...waking up !\n", __func__);
if (ret != 0)
return ret;
}
else
IRDA_DEBUG(1, "%s(), found immediately !\n",
- __FUNCTION__);
+ __func__);
/* Tell IrLMP that we have been notified */
irlmp_update_client(self->ckey, self->mask.word,
{
discovery_t *discovery;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
/*
* If log is missing this means that IrLAP was unable to perform the
int i = 0; /* How many we expired */
IRDA_ASSERT(log != NULL, return;);
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
spin_lock_irqsave(&log->hb_spinlock, flags);
{
ircomm = hashbin_new(HB_LOCK);
if (ircomm == NULL) {
- IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
+ IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__);
return -ENOMEM;
}
static void __exit ircomm_cleanup(void)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
struct ircomm_cb *self = NULL;
int ret;
- IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __func__ ,
service_type);
IRDA_ASSERT(ircomm != NULL, return NULL;);
*/
static int __ircomm_close(struct ircomm_cb *self)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Disconnect link if any */
ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
IRDA_ASSERT(self != NULL, return -EIO;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
entry = hashbin_remove(ircomm, self->line, NULL);
struct ircomm_info info;
int ret;
- IRDA_DEBUG(2 , "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2 , "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
{
int clen = 0;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Check if the packet contains data on the control channel */
if (skb->len > 0)
info->qos, info->max_data_size,
info->max_header_size, skb);
else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
}
}
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
struct ircomm_info *info)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
if (self->notify.connect_confirm )
self->notify.connect_confirm(self->notify.instance,
info->max_data_size,
info->max_header_size, skb);
else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
}
}
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -EFAULT;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
*/
void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(skb->len > 0, return;);
if (self->notify.data_indication)
self->notify.data_indication(self->notify.instance, self, skb);
else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
}
}
*/
if (unlikely(skb->len < (clen + 1))) {
IRDA_DEBUG(2, "%s() throwing away illegal frame\n",
- __FUNCTION__ );
+ __func__ );
return;
}
ircomm_data_indication(self, skb);
else {
IRDA_DEBUG(4, "%s(), data was control info only!\n",
- __FUNCTION__ );
+ __func__ );
}
}
{
int ret;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -EFAULT;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
static void ircomm_control_indication(struct ircomm_cb *self,
struct sk_buff *skb, int clen)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Use udata for delivering data on the control channel */
if (self->notify.udata_indication) {
* see ircomm_tty_control_indication(). */
dev_kfree_skb(ctrl_skb);
} else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
}
}
struct ircomm_info info;
int ret;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
struct ircomm_info *info)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(info != NULL, return;);
self->notify.disconnect_indication(self->notify.instance, self,
info->reason, skb);
} else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
}
}
*/
void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
ircomm_connect_indication(self, skb, info);
break;
default:
- IRDA_DEBUG(4, "%s(), unknown event: %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(4, "%s(), unknown event: %s\n", __func__ ,
ircomm_event[event]);
ret = -EINVAL;
}
ircomm_disconnect_indication(self, skb, info);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event: %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(0, "%s(), unknown event: %s\n", __func__ ,
ircomm_event[event]);
ret = -EINVAL;
}
ircomm_disconnect_indication(self, skb, info);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ ,
ircomm_event[event]);
ret = -EINVAL;
}
ret = self->issue.disconnect_request(self, skb, info);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ ,
ircomm_event[event]);
ret = -EINVAL;
}
int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb, struct ircomm_info *info)
{
- IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+ IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __func__ ,
ircomm_state[self->state], ircomm_event[event]);
return (*state[self->state])(self, event, skb, info);
{
self->state = state;
- IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __FUNCTION__ ,
+ IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __func__ ,
ircomm_state[self->state], self->service_type);
}
{
int ret = 0;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
struct sk_buff *tx_skb;
int ret;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
/* Any userdata supplied? */
if (userdata == NULL) {
struct sk_buff *tx_skb;
int ret;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
if (!userdata) {
tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
cb = (struct irda_skb_cb *) skb->cb;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
line = cb->line;
self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL);
if (!self) {
- IRDA_DEBUG(2, "%s(), didn't find myself\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), didn't find myself\n", __func__ );
return;
}
self->pkt_count--;
if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) {
- IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __func__ );
self->flow_status = FLOW_START;
if (self->notify.flow_indication)
self->notify.flow_indication(self->notify.instance,
cb->line = self->line;
- IRDA_DEBUG(4, "%s(), sending frame\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s(), sending frame\n", __func__ );
/* Don't forget to refcount it - see ircomm_tty_do_softint() */
skb_get(skb);
skb->destructor = ircomm_lmp_flow_control;
if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
- IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __func__ );
self->flow_status = FLOW_STOP;
if (self->notify.flow_indication)
self->notify.flow_indication(self->notify.instance,
}
ret = irlmp_data_request(self->lsap, skb);
if (ret) {
- IRDA_ERROR("%s(), failed\n", __FUNCTION__);
+ IRDA_ERROR("%s(), failed\n", __func__);
/* irlmp_data_request already free the packet */
}
{
struct ircomm_cb *self = (struct ircomm_cb *) instance;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
struct ircomm_cb *self = (struct ircomm_cb *)instance;
struct ircomm_info info;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
{
notify_t notify;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
/* Register callbacks */
irda_notify_init(¬ify);
self->lsap = irlmp_open_lsap(LSAP_ANY, ¬ify, 0);
if (!self->lsap) {
- IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __FUNCTION__ );
+ IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __func__ );
return -1;
}
self->slsap_sel = self->lsap->slsap_sel;
struct sk_buff *skb;
int count;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
count = irda_param_insert(self, pi, skb_tail_pointer(skb),
skb_tailroom(skb), &ircomm_param_info);
if (count < 0) {
- IRDA_WARNING("%s(), no room for parameter!\n", __FUNCTION__);
+ IRDA_WARNING("%s(), no room for parameter!\n", __func__);
spin_unlock_irqrestore(&self->spinlock, flags);
return -1;
}
spin_unlock_irqrestore(&self->spinlock, flags);
- IRDA_DEBUG(2, "%s(), skb->len=%d\n", __FUNCTION__ , skb->len);
+ IRDA_DEBUG(2, "%s(), skb->len=%d\n", __func__ , skb->len);
if (flush) {
/* ircomm_tty_do_softint will take care of the rest */
service_type &= self->service_type;
if (!service_type) {
IRDA_DEBUG(2,
- "%s(), No common service type to use!\n", __FUNCTION__ );
+ "%s(), No common service type to use!\n", __func__ );
return -1;
}
- IRDA_DEBUG(0, "%s(), services in common=%02x\n", __FUNCTION__ ,
+ IRDA_DEBUG(0, "%s(), services in common=%02x\n", __func__ ,
service_type);
/*
else if (service_type & IRCOMM_3_WIRE_RAW)
self->settings.service_type = IRCOMM_3_WIRE_RAW;
- IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __FUNCTION__ ,
+ IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __func__ ,
self->settings.service_type);
/*
else {
self->settings.port_type = (__u8) param->pv.i;
- IRDA_DEBUG(0, "%s(), port type=%d\n", __FUNCTION__ ,
+ IRDA_DEBUG(0, "%s(), port type=%d\n", __func__ ,
self->settings.port_type);
}
return 0;
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get) {
- IRDA_DEBUG(0, "%s(), not imp!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), not imp!\n", __func__ );
} else {
- IRDA_DEBUG(0, "%s(), port-name=%s\n", __FUNCTION__ , param->pv.c);
+ IRDA_DEBUG(0, "%s(), port-name=%s\n", __func__ , param->pv.c);
strncpy(self->settings.port_name, param->pv.c, 32);
}
else
self->settings.data_rate = param->pv.i;
- IRDA_DEBUG(2, "%s(), data rate = %d\n", __FUNCTION__ , param->pv.i);
+ IRDA_DEBUG(2, "%s(), data rate = %d\n", __func__ , param->pv.i);
return 0;
}
else
self->settings.flow_control = (__u8) param->pv.i;
- IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __FUNCTION__ , (__u8) param->pv.i);
+ IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __func__ , (__u8) param->pv.i);
return 0;
}
self->settings.xonxoff[1] = (__u16) param->pv.i >> 8;
}
- IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __FUNCTION__ ,
+ IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ ,
param->pv.i & 0xff, param->pv.i >> 8);
return 0;
self->settings.enqack[1] = (__u16) param->pv.i >> 8;
}
- IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __FUNCTION__ ,
+ IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ ,
param->pv.i & 0xff, param->pv.i >> 8);
return 0;
static int ircomm_param_line_status(void *instance, irda_param_t *param,
int get)
{
- IRDA_DEBUG(2, "%s(), not impl.\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), not impl.\n", __func__ );
return 0;
}
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
__u8 dce;
- IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __FUNCTION__ , (__u8) param->pv.i);
+ IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __func__ , (__u8) param->pv.i);
dce = (__u8) param->pv.i;
/* Check if any of the settings have changed */
if (dce & 0x0f) {
if (dce & IRCOMM_DELTA_CTS) {
- IRDA_DEBUG(2, "%s(), CTS \n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), CTS \n", __func__ );
}
}
{
notify_t notify;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
/* Register callbacks */
irda_notify_init(¬ify);
self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
¬ify);
if (!self->tsap) {
- IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __func__ );
return -1;
}
self->slsap_sel = self->tsap->stsap_sel;
{
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
IRDA_ASSERT(skb != NULL, return -1;);
- IRDA_DEBUG(2, "%s(), clen=%d\n", __FUNCTION__ , clen);
+ IRDA_DEBUG(2, "%s(), clen=%d\n", __func__ , clen);
/*
* Insert clen field, currently we either send data only, or control
ret = irttp_data_request(self->tsap, skb);
if (ret) {
- IRDA_ERROR("%s(), failed\n", __FUNCTION__);
+ IRDA_ERROR("%s(), failed\n", __func__);
/* irttp_data_request already free the packet */
}
{
struct ircomm_cb *self = (struct ircomm_cb *) instance;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
if (max_sdu_size != TTP_SAR_DISABLE) {
IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
- __FUNCTION__);
+ __func__);
goto out;
}
struct ircomm_cb *self = (struct ircomm_cb *)instance;
struct ircomm_info info;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
if (max_sdu_size != TTP_SAR_DISABLE) {
IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
- __FUNCTION__);
+ __func__);
goto out;
}
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
{
struct ircomm_cb *self = (struct ircomm_cb *) instance;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
return -ENOMEM;
ircomm_tty = hashbin_new(HB_LOCK);
if (ircomm_tty == NULL) {
- IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
+ IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__);
put_tty_driver(driver);
return -ENOMEM;
}
tty_set_operations(driver, &ops);
if (tty_register_driver(driver)) {
IRDA_ERROR("%s(): Couldn't register serial driver\n",
- __FUNCTION__);
+ __func__);
put_tty_driver(driver);
return -1;
}
static void __exit __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
{
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
ret = tty_unregister_driver(driver);
if (ret) {
IRDA_ERROR("%s(), failed to unregister driver\n",
- __FUNCTION__);
+ __func__);
return;
}
notify_t notify;
int ret = -ENODEV;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
/* Check if already open */
if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) {
- IRDA_DEBUG(2, "%s(), already open so break out!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ );
return 0;
}
/* Connect IrCOMM link with remote device */
ret = ircomm_tty_attach_cable(self);
if (ret < 0) {
- IRDA_ERROR("%s(), error attaching cable!\n", __FUNCTION__);
+ IRDA_ERROR("%s(), error attaching cable!\n", __func__);
goto err;
}
unsigned long flags;
struct tty_struct *tty;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
tty = self->tty;
if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
/* nonblock mode is set or port is not enabled */
self->flags |= ASYNC_NORMAL_ACTIVE;
- IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __FUNCTION__ );
+ IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ );
return 0;
}
if (tty->termios->c_cflag & CLOCAL) {
- IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ );
+ IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __func__ );
do_clocal = 1;
}
unsigned long flags;
int ret;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
line = tty->index;
if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
/* No, so make new instance */
self = kzalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
if (self == NULL) {
- IRDA_ERROR("%s(), kmalloc failed!\n", __FUNCTION__);
+ IRDA_ERROR("%s(), kmalloc failed!\n", __func__);
return -ENOMEM;
}
self->tty = tty;
spin_unlock_irqrestore(&self->spinlock, flags);
- IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __FUNCTION__ , tty->driver->name,
+ IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
self->line, self->open_count);
/* Not really used by us, but lets do it anyway */
if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) {
IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
- __FUNCTION__);
+ __func__);
return -ERESTARTSYS;
}
self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
/* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
self->settings.dce = IRCOMM_CTS | IRCOMM_CD | IRCOMM_DSR | IRCOMM_RI; /* Default line settings */
- IRDA_DEBUG(2, "%s(), IrCOMM device\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IrCOMM device\n", __func__ );
} else {
- IRDA_DEBUG(2, "%s(), IrLPT device\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IrLPT device\n", __func__ );
self->service_type = IRCOMM_3_WIRE_RAW;
self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */
}
ret = ircomm_tty_block_til_ready(self, filp);
if (ret) {
IRDA_DEBUG(2,
- "%s(), returning after block_til_ready with %d\n", __FUNCTION__ ,
+ "%s(), returning after block_til_ready with %d\n", __func__ ,
ret);
return ret;
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned long flags;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
if (!tty)
return;
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&self->spinlock, flags);
- IRDA_DEBUG(0, "%s(), returning 1\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), returning 1\n", __func__ );
return;
}
* serial port won't be shutdown.
*/
IRDA_DEBUG(0, "%s(), bad serial port count; "
- "tty->count is 1, state->count is %d\n", __FUNCTION__ ,
+ "tty->count is 1, state->count is %d\n", __func__ ,
self->open_count);
self->open_count = 1;
}
if (--self->open_count < 0) {
IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n",
- __FUNCTION__, self->line, self->open_count);
+ __func__, self->line, self->open_count);
self->open_count = 0;
}
if (self->open_count) {
spin_unlock_irqrestore(&self->spinlock, flags);
- IRDA_DEBUG(0, "%s(), open count > 0\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ );
return;
}
unsigned long flags;
struct sk_buff *skb, *ctrl_skb;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if (!self || self->magic != IRCOMM_TTY_MAGIC)
return;
int len = 0;
int size;
- IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __FUNCTION__ , count,
+ IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __func__ , count,
tty->hw_stopped);
IRDA_ASSERT(self != NULL, return -1;);
* we don't mess up the original "safe skb" (see tx_data_size).
* Jean II */
if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) {
- IRDA_DEBUG(1, "%s() : not initialised\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s() : not initialised\n", __func__);
#ifdef IRCOMM_NO_TX_BEFORE_INIT
/* We didn't consume anything, TTY will retry */
return 0;
ret = self->max_data_size;
spin_unlock_irqrestore(&self->spinlock, flags);
}
- IRDA_DEBUG(2, "%s(), ret=%d\n", __FUNCTION__ , ret);
+ IRDA_DEBUG(2, "%s(), ret=%d\n", __func__ , ret);
return ret;
}
unsigned long orig_jiffies, poll_time;
unsigned long flags;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
ircomm_param_request(self, IRCOMM_DTE, TRUE);
- IRDA_DEBUG(1, "%s(), FLOW_START\n", __FUNCTION__ );
+ IRDA_DEBUG(1, "%s(), FLOW_START\n", __func__ );
}
ircomm_flow_request(self->ircomm, FLOW_START);
}
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags))
return;
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned long flags;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
*/
static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch)
{
- IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), not impl\n", __func__ );
}
/*
struct tty_struct *tty;
int status;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
}
if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
IRDA_DEBUG(2,
- "%s(), ircomm%d CD now %s...\n", __FUNCTION__ , self->line,
+ "%s(), ircomm%d CD now %s...\n", __func__ , self->line,
(status & IRCOMM_CD) ? "on" : "off");
if (status & IRCOMM_CD) {
wake_up_interruptible(&self->open_wait);
} else {
IRDA_DEBUG(2,
- "%s(), Doing serial hangup..\n", __FUNCTION__ );
+ "%s(), Doing serial hangup..\n", __func__ );
if (tty)
tty_hangup(tty);
if (tty->hw_stopped) {
if (status & IRCOMM_CTS) {
IRDA_DEBUG(2,
- "%s(), CTS tx start...\n", __FUNCTION__ );
+ "%s(), CTS tx start...\n", __func__ );
tty->hw_stopped = 0;
/* Wake up processes blocked on open */
} else {
if (!(status & IRCOMM_CTS)) {
IRDA_DEBUG(2,
- "%s(), CTS tx stop...\n", __FUNCTION__ );
+ "%s(), CTS tx stop...\n", __func__ );
tty->hw_stopped = 1;
}
}
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
if (!self->tty) {
- IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), no tty!\n", __func__ );
return 0;
}
* params, we can just as well declare the hardware for running.
*/
if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
- IRDA_DEBUG(0, "%s(), polling for line settings!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ );
ircomm_param_request(self, IRCOMM_POLL, TRUE);
/* We can just as well declare the hardware for running */
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
int clen;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
switch (cmd) {
case FLOW_START:
- IRDA_DEBUG(2, "%s(), hw start!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), hw start!\n", __func__ );
tty->hw_stopped = 0;
/* ircomm_tty_do_softint will take care of the rest */
break;
default: /* If we get here, something is very wrong, better stop */
case FLOW_STOP:
- IRDA_DEBUG(2, "%s(), hw stopped!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ );
tty->hw_stopped = 1;
break;
}
*/
int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
{
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
/* Check if somebody has already connected to us */
if (ircomm_is_connected(self->ircomm)) {
- IRDA_DEBUG(0, "%s(), already connected!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), already connected!\n", __func__ );
return 0;
}
*/
void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
{
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
__u8 oct_seq[6];
__u16 hints;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
* Set default values, but only if the application for some reason
* haven't set them already
*/
- IRDA_DEBUG(2, "%s(), data-rate = %d\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), data-rate = %d\n", __func__ ,
self->settings.data_rate);
if (!self->settings.data_rate)
self->settings.data_rate = 9600;
- IRDA_DEBUG(2, "%s(), data-format = %d\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), data-format = %d\n", __func__ ,
self->settings.data_format);
if (!self->settings.data_format)
self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */
- IRDA_DEBUG(2, "%s(), flow-control = %d\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), flow-control = %d\n", __func__ ,
self->settings.flow_control);
/*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
struct ircomm_tty_cb *self;
struct ircomm_tty_info info;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Important note :
* We need to drop all passive discoveries.
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
/* Check if request succeeded */
if (result != IAS_SUCCESS) {
- IRDA_DEBUG(4, "%s(), got NULL value!\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s(), got NULL value!\n", __func__ );
return;
}
switch (value->type) {
case IAS_OCT_SEQ:
- IRDA_DEBUG(2, "%s(), got octet sequence\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), got octet sequence\n", __func__ );
irda_param_extract_all(self, value->t.oct_seq, value->len,
&ircomm_param_info);
break;
case IAS_INTEGER:
/* Got LSAP selector */
- IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __func__ ,
value->t.integer);
if (value->t.integer == -1) {
- IRDA_DEBUG(0, "%s(), invalid value!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), invalid value!\n", __func__ );
} else
self->dlsap_sel = value->t.integer;
ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
break;
case IAS_MISSING:
- IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __func__ );
break;
default:
- IRDA_DEBUG(0, "%s(), got unknown type!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), got unknown type!\n", __func__ );
break;
}
irias_delete_value(value);
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
int clen;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
*/
void ircomm_tty_link_established(struct ircomm_tty_cb *self)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
* line.
*/
if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
- IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
return;
} else {
- IRDA_DEBUG(1, "%s(), starting hardware!\n", __FUNCTION__ );
+ IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );
self->tty->hw_stopped = 0;
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
ircomm_tty_state[self->state], ircomm_tty_event[event]);
return (*state[self->state])(self, event, skb, info);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __func__ ,
ircomm_tty_state[self->state], self->service_type);
*/
self->state = state;
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
case IRCOMM_TTY_ATTACH_CABLE:
if (self->iriap) {
IRDA_WARNING("%s(), busy with a previous query\n",
- __FUNCTION__);
+ __func__);
return -EBUSY;
}
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
ircomm_tty_event[event]);
ret = -EINVAL;
}
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
if (self->iriap) {
IRDA_WARNING("%s(), busy with a previous query\n",
- __FUNCTION__);
+ __func__);
return -EBUSY;
}
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
ircomm_tty_event[event]);
ret = -EINVAL;
}
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
case IRCOMM_TTY_GOT_PARAMETERS:
if (self->iriap) {
IRDA_WARNING("%s(), busy with a previous query\n",
- __FUNCTION__);
+ __func__);
return -EBUSY;
}
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
ircomm_tty_event[event]);
ret = -EINVAL;
}
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
ircomm_tty_event[event]);
ret = -EINVAL;
}
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
ircomm_tty_event[event]);
ret = -EINVAL;
}
self->settings.dce = IRCOMM_DELTA_CD;
ircomm_tty_check_modem_status(self);
} else {
- IRDA_DEBUG(0, "%s(), hanging up!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
if (self->tty)
tty_hangup(self->tty);
}
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
ircomm_tty_event[event]);
ret = -EINVAL;
}
unsigned cflag, cval;
int baud;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if (!self->tty || !self->tty->termios || !self->ircomm)
return;
self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
/* This got me. Bummer. Jean II */
if (self->service_type == IRCOMM_3_WIRE_RAW)
- IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __FUNCTION__);
+ IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__);
} else {
self->flags &= ~ASYNC_CTS_FLOW;
self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned int cflag = tty->termios->c_cflag;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(tty->termios->c_iflag) ==
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned int result;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
if (!retinfo)
return -EFAULT;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
memset(&info, 0, sizeof(info));
info.line = self->line;
struct serial_struct new_serial;
struct ircomm_tty_cb old_state, *state;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
break;
case TIOCGICOUNT:
- IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __func__ );
#if 0
save_flags(flags); cli();
cnow = driver->icount;
void irda_device_cleanup(void)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
{
struct irlap_cb *self;
- IRDA_DEBUG(4, "%s(%s)\n", __FUNCTION__, status ? "TRUE" : "FALSE");
+ IRDA_DEBUG(4, "%s(%s)\n", __func__, status ? "TRUE" : "FALSE");
self = (struct irlap_cb *) dev->atalk_ptr;
struct if_irda_req req;
int ret;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
if (!dev->do_ioctl) {
IRDA_ERROR("%s: do_ioctl not impl. by device driver\n",
- __FUNCTION__);
+ __func__);
return -1;
}
int count = 0;
int timeout;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
IRDA_ASSERT(task != NULL, return -1;);
IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
timeout = task->function(task);
if (count++ > 100) {
IRDA_ERROR("%s: error in task handler!\n",
- __FUNCTION__);
+ __func__);
irda_task_delete(task);
return TRUE;
}
} while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
if (timeout < 0) {
- IRDA_ERROR("%s: Error executing task!\n", __FUNCTION__);
+ IRDA_ERROR("%s: Error executing task!\n", __func__);
irda_task_delete(task);
return TRUE;
}
finished = FALSE;
} else {
IRDA_DEBUG(0, "%s(), not finished, and no timeout!\n",
- __FUNCTION__);
+ __func__);
finished = FALSE;
}
{
struct irda_task *task;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
task = (struct irda_task *) data;
irias_objects = hashbin_new(HB_LOCK);
if (!irias_objects) {
IRDA_WARNING("%s: Can't allocate irias_objects hashbin!\n",
- __FUNCTION__);
+ __func__);
hashbin_delete(iriap, NULL);
return -ENOMEM;
}
*/
server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
if (!server) {
- IRDA_DEBUG(0, "%s(), unable to open server\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unable to open server\n", __func__);
return -1;
}
iriap_register_lsap(server, LSAP_IAS, IAS_SERVER);
{
struct iriap_cb *self;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
self = kzalloc(sizeof(*self), GFP_ATOMIC);
if (!self) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
return NULL;
}
*/
static void __iriap_close(struct iriap_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
{
struct iriap_cb *entry;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
{
notify_t notify;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
irda_notify_init(¬ify);
notify.connect_confirm = iriap_connect_confirm;
self->lsap = irlmp_open_lsap(slsap_sel, ¬ify, 0);
if (self->lsap == NULL) {
- IRDA_ERROR("%s: Unable to allocated LSAP!\n", __FUNCTION__);
+ IRDA_ERROR("%s: Unable to allocated LSAP!\n", __func__);
return -1;
}
self->slsap_sel = self->lsap->slsap_sel;
{
struct iriap_cb *self;
- IRDA_DEBUG(4, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]);
+ IRDA_DEBUG(4, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
self = (struct iriap_cb *) instance;
dev_kfree_skb(skb);
if (self->mode == IAS_CLIENT) {
- IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), disconnect as client\n", __func__);
iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION,
if (self->confirm)
self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
} else {
- IRDA_DEBUG(4, "%s(), disconnect as server\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), disconnect as server\n", __func__);
iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION,
NULL);
iriap_close(self);
{
struct sk_buff *tx_skb;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
if (tx_skb == NULL) {
IRDA_DEBUG(0,
"%s(), Could not allocate an sk_buff of length %d\n",
- __FUNCTION__, LMP_MAX_HEADER);
+ __func__, LMP_MAX_HEADER);
return;
}
/* Get length, MSB first */
len = be16_to_cpu(get_unaligned((__be16 *)(fp+n))); n += 2;
- IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len);
+ IRDA_DEBUG(4, "%s(), len=%d\n", __func__, len);
/* Get object ID, MSB first */
obj_id = be16_to_cpu(get_unaligned((__be16 *)(fp+n))); n += 2;
type = fp[n++];
- IRDA_DEBUG(4, "%s(), Value type = %d\n", __FUNCTION__, type);
+ IRDA_DEBUG(4, "%s(), Value type = %d\n", __func__, type);
switch (type) {
case IAS_INTEGER:
value = irias_new_integer_value(tmp_cpu32);
/* Legal values restricted to 0x01-0x6f, page 15 irttp */
- IRDA_DEBUG(4, "%s(), lsap=%d\n", __FUNCTION__, value->t.integer);
+ IRDA_DEBUG(4, "%s(), lsap=%d\n", __func__, value->t.integer);
break;
case IAS_STRING:
charset = fp[n++];
/* case CS_UNICODE: */
default:
IRDA_DEBUG(0, "%s(), charset %s, not supported\n",
- __FUNCTION__, ias_charset_types[charset]);
+ __func__, ias_charset_types[charset]);
/* Aborting, close connection! */
iriap_disconnect_request(self);
/* break; */
}
value_len = fp[n++];
- IRDA_DEBUG(4, "%s(), strlen=%d\n", __FUNCTION__, value_len);
+ IRDA_DEBUG(4, "%s(), strlen=%d\n", __func__, value_len);
/* Make sure the string is null-terminated */
fp[n+value_len] = 0x00;
if (self->confirm)
self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
else {
- IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), missing handler!\n", __func__);
irias_delete_value(value);
}
}
__be16 tmp_be16;
__u8 *fp;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len;
break;
case IAS_MISSING:
- IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__);
+ IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __func__);
skb_put(tx_skb, 1);
fp[n++] = value->type;
break;
default:
- IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), type not implemented!\n", __func__);
break;
}
iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb);
__u8 *fp;
int n;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
struct sk_buff *tx_skb;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
self->saddr, self->daddr,
NULL, NULL);
if (ret < 0) {
- IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
}
}
{
struct iriap_cb *self, *new;
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
self = (struct iriap_cb *) instance;
/* Start new server */
new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
if (!new) {
- IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), open failed\n", __func__);
goto out;
}
/* Now attach up the new "socket" */
new->lsap = irlmp_dup(self->lsap, new);
if (!new->lsap) {
- IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
goto out;
}
__u8 *frame;
__u8 opcode;
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
self = (struct iriap_cb *) instance;
if (self->mode == IAS_SERVER) {
/* Call server */
- IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), Calling server!\n", __func__);
iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
goto out;
}
if (~opcode & IAP_LST) {
IRDA_WARNING("%s:, IrIAS multiframe commands or "
"results is not implemented yet!\n",
- __FUNCTION__);
+ __func__);
goto out;
}
/* Check for ack frames since they don't contain any data */
if (opcode & IAP_ACK) {
- IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() Got ack frame!\n", __func__);
goto out;
}
iriap_getvaluebyclass_confirm(self, skb);
break;
case IAS_CLASS_UNKNOWN:
- IRDA_DEBUG(1, "%s(), No such class!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), No such class!\n", __func__);
/* Finished, close connection! */
iriap_disconnect_request(self);
self->priv);
break;
case IAS_ATTRIB_UNKNOWN:
- IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), No such attribute!\n", __func__);
/* Finished, close connection! */
iriap_disconnect_request(self);
}
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__,
+ IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __func__,
opcode);
break;
}
__u8 *fp;
__u8 opcode;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
opcode = fp[0];
if (~opcode & 0x80) {
IRDA_WARNING("%s: IrIAS multiframe commands or results "
- "is not implemented yet!\n", __FUNCTION__);
+ "is not implemented yet!\n", __func__);
return;
}
opcode &= 0x7f; /* Mask away LST bit */
switch (opcode) {
case GET_INFO_BASE:
IRDA_WARNING("%s: GetInfoBaseDetails not implemented yet!\n",
- __FUNCTION__);
+ __func__);
break;
case GET_VALUE_BY_CLASS:
iriap_getvaluebyclass_indication(self, skb);
case IAP_LM_DISCONNECT_INDICATION:
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
+ IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
break;
}
}
iriap_next_client_state(self, S_DISCONNECT);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
+ IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
break;
}
}
iriap_next_call_state(self, S_OUTSTANDING);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
+ IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
break;
}
}
static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
}
/*
iriap_next_call_state(self, S_WAIT_FOR_CALL);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
+ IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
break;
}
}
static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
}
/*
static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
}
static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
}
/**************************************************************************
case IAP_LM_CONNECT_INDICATION:
tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (tx_skb == NULL) {
- IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: unable to malloc!\n", __func__);
return;
}
iriap_next_r_connect_state(self, R_RECEIVING);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event);
+ IRDA_DEBUG(0, "%s(), unknown event %d\n", __func__, event);
break;
}
}
static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
switch (event) {
case IAP_LM_DISCONNECT_INDICATION:
iriap_next_r_connect_state(self, R_WAITING);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
break;
}
}
static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
}
static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
}
/*
static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
switch (event) {
case IAP_RECV_F_LST:
iriap_call_indication(self, skb);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
break;
}
}
static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(self != NULL, return;);
irlmp_data_request(self->lsap, skb);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
break;
}
}
static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), event=%d\n", __FUNCTION__, event);
+ IRDA_DEBUG(0, "%s(), event=%d\n", __func__, event);
switch (event) {
case IAP_RECV_F_LST:
{
struct ias_object *obj;
- IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG( 4, "%s()\n", __func__);
obj = kzalloc(sizeof(struct ias_object), GFP_ATOMIC);
if (obj == NULL) {
IRDA_WARNING("%s(), Unable to allocate object!\n",
- __FUNCTION__);
+ __func__);
return NULL;
}
obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
if (!obj->name) {
IRDA_WARNING("%s(), Unable to allocate name!\n",
- __FUNCTION__);
+ __func__);
kfree(obj);
return NULL;
}
if (obj->attribs == NULL) {
IRDA_WARNING("%s(), Unable to allocate attribs!\n",
- __FUNCTION__);
+ __func__);
kfree(obj->name);
kfree(obj);
return NULL;
node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj);
if (!node)
IRDA_DEBUG( 0, "%s(), object already removed!\n",
- __FUNCTION__);
+ __func__);
/* Destroy */
__irias_delete_object(obj);
/* Find object */
obj = hashbin_lock_find(irias_objects, 0, obj_name);
if (obj == NULL) {
- IRDA_WARNING("%s: Unable to find object: %s\n", __FUNCTION__,
+ IRDA_WARNING("%s: Unable to find object: %s\n", __func__,
obj_name);
return -1;
}
attrib = hashbin_find(obj->attribs, 0, attrib_name);
if (attrib == NULL) {
IRDA_WARNING("%s: Unable to find attribute: %s\n",
- __FUNCTION__, attrib_name);
+ __func__, attrib_name);
spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
return -1;
}
if ( attrib->value->type != new_value->type) {
IRDA_DEBUG( 0, "%s(), changing value type not allowed!\n",
- __FUNCTION__);
+ __func__);
spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
return -1;
}
attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC);
if (attrib == NULL) {
IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __FUNCTION__);
+ __func__);
return;
}
attrib->value = irias_new_integer_value(value);
if (!attrib->name || !attrib->value) {
IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __FUNCTION__);
+ __func__);
if (attrib->value)
irias_delete_value(attrib->value);
kfree(attrib->name);
attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC);
if (attrib == NULL) {
IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __FUNCTION__);
+ __func__);
return;
}
attrib->value = irias_new_octseq_value( octets, len);
if (!attrib->name || !attrib->value) {
IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __FUNCTION__);
+ __func__);
if (attrib->value)
irias_delete_value(attrib->value);
kfree(attrib->name);
attrib = kzalloc(sizeof( struct ias_attrib), GFP_ATOMIC);
if (attrib == NULL) {
IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __FUNCTION__);
+ __func__);
return;
}
attrib->value = irias_new_string_value(value);
if (!attrib->name || !attrib->value) {
IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __FUNCTION__);
+ __func__);
if (attrib->value)
irias_delete_value(attrib->value);
kfree(attrib->name);
value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
if (value == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
return NULL;
}
value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
if (value == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
return NULL;
}
value->charset = CS_ASCII;
value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
if (!value->t.string) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
kfree(value);
return NULL;
}
value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
if (value == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
return NULL;
}
value->t.oct_seq = kmemdup(octseq, len, GFP_ATOMIC);
if (value->t.oct_seq == NULL){
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
kfree(value);
return NULL;
}
value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
if (value == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
return NULL;
}
*/
void irias_delete_value(struct ias_value *value)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(value != NULL, return;);
kfree(value->t.oct_seq);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Unknown value type!\n", __func__);
break;
}
kfree(value);
{
struct irlan_cb *self = (struct irlan_cb *) data;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
irda_start_timer(&self->client.kick_timer, timeout, (void *) self,
irlan_client_kick_timer_expired);
*/
void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
{
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(1, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
if ((self->client.state != IRLAN_IDLE) ||
(self->provider.access_type == ACCESS_DIRECT))
{
- IRDA_DEBUG(0, "%s(), already awake!\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), already awake!\n", __func__ );
return;
}
self->daddr = daddr;
if (self->disconnect_reason == LM_USER_REQUEST) {
- IRDA_DEBUG(0, "%s(), still stopped by user\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s(), still stopped by user\n", __func__ );
return;
}
struct irlan_cb *self;
__u32 saddr, daddr;
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(1, "%s()\n", __func__ );
IRDA_ASSERT(discovery != NULL, return;);
if (self) {
IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;);
- IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __FUNCTION__ ,
+ IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __func__ ,
daddr);
irlan_client_wakeup(self, saddr, daddr);
{
struct irlan_cb *self;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
self = (struct irlan_cb *) instance;
irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
/* Ready for a new command */
- IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __func__ );
self->client.tx_busy = FALSE;
/* Check if we have some queued commands waiting to be sent */
struct tsap_cb *tsap;
struct sk_buff *skb;
- IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason);
+ IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason);
self = (struct irlan_cb *) instance;
tsap = (struct tsap_cb *) sap;
struct tsap_cb *tsap;
notify_t notify;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify);
if (!tsap) {
- IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
return;
}
self->client.tsap_ctrl = tsap;
{
struct irlan_cb *self;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
self = (struct irlan_cb *) instance;
IRDA_ASSERT(skb != NULL, return;);
- IRDA_DEBUG(4, "%s() skb->len=%d\n", __FUNCTION__ , (int) skb->len);
+ IRDA_DEBUG(4, "%s() skb->len=%d\n", __func__ , (int) skb->len);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
if (!skb) {
- IRDA_ERROR("%s(), Got NULL skb!\n", __FUNCTION__);
+ IRDA_ERROR("%s(), Got NULL skb!\n", __func__);
return;
}
frame = skb->data;
/* How many parameters? */
count = frame[1];
- IRDA_DEBUG(4, "%s(), got %d parameters\n", __FUNCTION__ , count);
+ IRDA_DEBUG(4, "%s(), got %d parameters\n", __func__ , count);
ptr = frame+2;
for (i=0; i<count;i++) {
ret = irlan_extract_param(ptr, name, value, &val_len);
if (ret < 0) {
- IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ );
break;
}
ptr += ret;
int i;
DECLARE_MAC_BUF(mac);
- IRDA_DEBUG(4, "%s(), parm=%s\n", __FUNCTION__ , param);
+ IRDA_DEBUG(4, "%s(), parm=%s\n", __func__ , param);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
else if (strcmp(value, "HOSTED") == 0)
self->client.access_type = ACCESS_HOSTED;
else {
- IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ );
}
}
/* IRLAN version */
memcpy(&tmp_cpu, value, 2); /* Align value */
le16_to_cpus(&tmp_cpu); /* Convert to host order */
self->client.recv_arb_val = tmp_cpu;
- IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __FUNCTION__ ,
+ IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __func__ ,
self->client.recv_arb_val);
}
if (strcmp(param, "MAX_FRAME") == 0) {
memcpy(&tmp_cpu, value, 2); /* Align value */
le16_to_cpus(&tmp_cpu); /* Convert to host order */
self->client.max_frame = tmp_cpu;
- IRDA_DEBUG(4, "%s(), max frame=%d\n", __FUNCTION__ ,
+ IRDA_DEBUG(4, "%s(), max frame=%d\n", __func__ ,
self->client.max_frame);
}
{
struct irlan_cb *self;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(priv != NULL, return;);
/* Check if request succeeded */
if (result != IAS_SUCCESS) {
- IRDA_DEBUG(2, "%s(), got NULL value!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), got NULL value!\n", __func__ );
irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
NULL);
return;
irias_delete_value(value);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown type!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), unknown type!\n", __func__ );
break;
}
irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
case IRLAN_DISCOVERY_INDICATION:
if (self->client.iriap) {
IRDA_WARNING("%s(), busy with a previous query\n",
- __FUNCTION__);
+ __func__);
return -EBUSY;
}
"IrLAN", "IrDA:TinyTP:LsapSel");
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
break;
default:
- IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
irlan_next_client_state(self, IRLAN_CONN);
break;
case IRLAN_IAS_PROVIDER_NOT_AVAIL:
- IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__ );
irlan_next_client_state(self, IRLAN_IDLE);
/* Give the client a kick! */
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
{
struct qos_info qos;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
irlan_next_client_state(self, IRLAN_DATA);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ );
break;
}
break;
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
{
struct qos_info qos;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
} else if (self->client.recv_arb_val >
self->provider.send_arb_val)
{
- IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __func__ );
}
break;
case IRLAN_DATA_CONNECT_INDICATION:
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
irlan_next_client_state(self, IRLAN_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if (skb)
dev_kfree_skb(skb);
static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if (skb)
dev_kfree_skb(skb);
struct irlan_cb *new;
__u16 hints;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
#ifdef CONFIG_PROC_FS
{ struct proc_dir_entry *proc;
}
#endif /* CONFIG_PROC_FS */
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
hints = irlmp_service_to_hint(S_LAN);
/* Register with IrLMP as a client */
{
struct irlan_cb *self, *next;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
irlmp_unregister_client(ckey);
irlmp_unregister_service(skey);
struct net_device *dev;
struct irlan_cb *self;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Create network device with irlan */
dev = alloc_irlandev(eth ? "eth%d" : "irlan%d");
if (register_netdev(dev)) {
IRDA_DEBUG(2, "%s(), register_netdev() failed!\n",
- __FUNCTION__ );
+ __func__ );
self = NULL;
free_netdev(dev);
} else {
*/
static void __irlan_close(struct irlan_cb *self)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
ASSERT_RTNL();
IRDA_ASSERT(self != NULL, return;);
struct irlan_cb *self;
struct tsap_cb *tsap;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
self = (struct irlan_cb *) instance;
tsap = (struct tsap_cb *) sap;
self->max_sdu_size = max_sdu_size;
self->max_header_size = max_header_size;
- IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s: We are now connected!\n", __func__);
del_timer(&self->watchdog_timer);
/* TODO: we could set the MTU depending on the max_sdu_size */
- IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s: We are now connected!\n", __func__);
del_timer(&self->watchdog_timer);
/*
struct irlan_cb *self;
struct tsap_cb *tsap;
- IRDA_DEBUG(0, "%s(), reason=%d\n", __FUNCTION__ , reason);
+ IRDA_DEBUG(0, "%s(), reason=%d\n", __func__ , reason);
self = (struct irlan_cb *) instance;
tsap = (struct tsap_cb *) sap;
switch (reason) {
case LM_USER_REQUEST: /* User request */
- IRDA_DEBUG(2, "%s(), User requested\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), User requested\n", __func__ );
break;
case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
- IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __func__ );
break;
case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */
- IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __func__ );
break;
case LM_LAP_RESET: /* IrLAP reset */
- IRDA_DEBUG(2, "%s(), IrLAP reset\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IrLAP reset\n", __func__ );
break;
case LM_INIT_DISCONNECT:
- IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __func__ );
break;
default:
- IRDA_ERROR("%s(), Unknown disconnect reason\n", __FUNCTION__);
+ IRDA_ERROR("%s(), Unknown disconnect reason\n", __func__);
break;
}
struct tsap_cb *tsap;
notify_t notify;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify);
if (!tsap) {
- IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
return;
}
self->tsap_data = tsap;
void irlan_close_tsaps(struct irlan_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
{
struct sk_buff *skb;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
if (irda_lock(&self->client.tx_busy) == FALSE)
return -EBUSY;
dev_kfree_skb(skb);
return -1;
}
- IRDA_DEBUG(2, "%s(), sending ...\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), sending ...\n", __func__ );
return irttp_data_request(self->client.tsap_ctrl, skb);
}
*/
static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Queue command */
skb_queue_tail(&self->client.txq, skb);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
int n=0;
if (skb == NULL) {
- IRDA_DEBUG(2, "%s(), Got NULL skb\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Got NULL skb\n", __func__ );
return 0;
}
IRDA_ASSERT(value_len > 0, return 0;);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __func__ );
return 0;
break;
}
/* Make space for data */
if (skb_tailroom(skb) < (param_len+value_len+3)) {
- IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __func__ );
return 0;
}
skb_put(skb, param_len+value_len+3);
__u16 val_len;
int n=0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
/* get length of parameter name (1 byte) */
name_len = buf[n++];
if (name_len > 254) {
- IRDA_DEBUG(2, "%s(), name_len > 254\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), name_len > 254\n", __func__ );
return -RSP_INVALID_COMMAND_FORMAT;
}
le16_to_cpus(&val_len); n+=2;
if (val_len > 1016) {
- IRDA_DEBUG(2, "%s(), parameter length to long\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), parameter length to long\n", __func__ );
return -RSP_INVALID_COMMAND_FORMAT;
}
*len = val_len;
{
struct irlan_cb *self = netdev_priv(dev);
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Ready to play! */
netif_stop_queue(dev); /* Wait until data link is ready */
{
struct irlan_cb *self = netdev_priv(dev);
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Stop device */
netif_stop_queue(dev);
}
if (skb->len < ETH_HLEN) {
IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",
- __FUNCTION__, skb->len);
+ __func__, skb->len);
++self->stats.rx_dropped;
dev_kfree_skb(skb);
return 0;
IRDA_ASSERT(dev != NULL, return;);
- IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __FUNCTION__,
+ IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __func__,
flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",
netif_running(dev));
{
struct irlan_cb *self = netdev_priv(dev);
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s()\n", __func__ );
/* Check if data channel has been connected yet */
if (self->client.state != IRLAN_DATA) {
- IRDA_DEBUG(1, "%s(), delaying!\n", __FUNCTION__ );
+ IRDA_DEBUG(1, "%s(), delaying!\n", __func__ );
return;
}
}
else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) {
/* Disable promiscuous mode, use normal mode. */
- IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ );
/* hardware_set_filter(NULL); */
irlan_set_multicast_filter(self, TRUE);
}
else if (dev->mc_count) {
- IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ );
/* Walk the address list, and load the filter */
/* hardware_set_filter(dev->mc_list); */
irlan_set_multicast_filter(self, TRUE);
}
else {
- IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __func__ );
irlan_set_multicast_filter(self, FALSE);
}
void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state)
{
- IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]);
+ IRDA_DEBUG(2, "%s(), %s\n", __func__ , irlan_state[state]);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state)
{
- IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]);
+ IRDA_DEBUG(2, "%s(), %s\n", __func__ , irlan_state[state]);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
{
__u8 *bytes;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
bytes = value;
* This is experimental!! DB.
*/
if (strcmp(param, "MODE") == 0) {
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
self->use_udata = TRUE;
return;
}
struct irlan_cb *self;
__u8 code;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
self = (struct irlan_cb *) instance;
irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb);
break;
case CMD_RECONNECT_DATA_CHAN:
- IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __FUNCTION__ );
- IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __func__ );
+ IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ );
break;
case CMD_CLOSE_DATA_CHAN:
IRDA_DEBUG(2, "Got CLOSE_DATA_CHAN command!\n");
- IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ );
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ );
break;
}
return 0;
struct tsap_cb *tsap;
__u32 saddr, daddr;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(0, "%s()\n", __func__ );
self = (struct irlan_cb *) instance;
tsap = (struct tsap_cb *) sap;
struct irlan_cb *self;
struct tsap_cb *tsap;
- IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason);
+ IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason);
self = (struct irlan_cb *) instance;
tsap = (struct tsap_cb *) sap;
IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
- IRDA_DEBUG(4, "%s(), skb->len=%d\n", __FUNCTION__ , (int)skb->len);
+ IRDA_DEBUG(4, "%s(), skb->len=%d\n", __func__ , (int)skb->len);
IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
for (i=0; i<count;i++) {
ret = irlan_extract_param(ptr, name, value, &val_len);
if (ret < 0) {
- IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ );
break;
}
ptr+=ret;
{
struct sk_buff *skb;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
irlan_insert_string_param(skb, "MEDIA", "802.5");
break;
default:
- IRDA_DEBUG(2, "%s(), unknown media type!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), unknown media type!\n", __func__ );
break;
}
irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED");
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown access type\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Unknown access type\n", __func__ );
break;
}
irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee);
irlan_filter_request(self, skb);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ );
break;
}
struct tsap_cb *tsap;
notify_t notify;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
tsap = irttp_open_tsap(LSAP_ANY, 1, ¬ify);
if (!tsap) {
- IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
+ IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
return -1;
}
self->provider.tsap_ctrl = tsap;
static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
irlan_next_provider_state( self, IRLAN_INFO);
break;
default:
- IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
irlan_next_provider_state(self, IRLAN_IDLE);
break;
default:
- IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
irlan_next_provider_state(self, IRLAN_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ IRDA_DEBUG(4, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
irlan_next_provider_state(self, IRLAN_IDLE);
break;
default:
- IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+ IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
irlap = hashbin_new(HB_LOCK);
if (irlap == NULL) {
IRDA_ERROR("%s: can't allocate irlap hashbin!\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
{
struct irlap_cb *self;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
/* Initialize the irlap structure. */
self = kzalloc(sizeof(struct irlap_cb), GFP_KERNEL);
{
struct irlap_cb *lap;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
/* Be sure that we manage to remove ourself from the hash */
lap = hashbin_remove(irlap, self->saddr, NULL);
if (!lap) {
- IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __func__);
return;
}
__irlap_close(lap);
*/
void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL);
}
void irlap_connect_request(struct irlap_cb *self, __u32 daddr,
struct qos_info *qos_user, int sniff)
{
- IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __FUNCTION__, daddr);
+ IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __func__, daddr);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
return;);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
return;);
#ifdef CONFIG_IRDA_ULTRA
void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_disconnect_request(struct irlap_cb *self)
{
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL);
break;
default:
- IRDA_DEBUG(2, "%s(), disconnect pending!\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), disconnect pending!\n", __func__);
self->disconnect_pending = TRUE;
break;
}
*/
void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
{
- IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lap_reasons[reason]);
+ IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, lap_reasons[reason]);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
switch (reason) {
case LAP_RESET_INDICATION:
- IRDA_DEBUG(1, "%s(), Sending reset request!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Sending reset request!\n", __func__);
irlap_do_event(self, RESET_REQUEST, NULL, NULL);
break;
case LAP_NO_RESPONSE: /* FALLTROUGH */
reason, NULL);
break;
default:
- IRDA_ERROR("%s: Unknown reason %d\n", __FUNCTION__, reason);
+ IRDA_ERROR("%s: Unknown reason %d\n", __func__, reason);
}
}
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(discovery != NULL, return;);
- IRDA_DEBUG(4, "%s(), nslots = %d\n", __FUNCTION__, discovery->nslots);
+ IRDA_DEBUG(4, "%s(), nslots = %d\n", __func__, discovery->nslots);
IRDA_ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
(discovery->nslots == 8) || (discovery->nslots == 16),
/* Discovery is only possible in NDM mode */
if (self->state != LAP_NDM) {
IRDA_DEBUG(4, "%s(), discovery only possible in NDM mode\n",
- __FUNCTION__);
+ __func__);
irlap_discovery_confirm(self, NULL);
/* Note : in theory, if we are not in NDM, we could postpone
* the discovery like we do for connection request.
if (self->discovery_log == NULL) {
IRDA_WARNING("%s(), Unable to allocate discovery log!\n",
- __FUNCTION__);
+ __func__);
return;
}
*/
void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_reset_indication(struct irlap_cb *self)
{
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_reset_confirm(void)
{
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
}
/*
{
/* nr as expected? */
if (nr == self->vs) {
- IRDA_DEBUG(4, "%s(), expected!\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), expected!\n", __func__);
return NR_EXPECTED;
}
*/
void irlap_initiate_connection_state(struct irlap_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
{
struct sk_buff *skb;
- IRDA_DEBUG(0, "%s(), setting speed to %d\n", __FUNCTION__, speed);
+ IRDA_DEBUG(0, "%s(), setting speed to %d\n", __func__, speed);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
* user may not have set all of them.
*/
if (qos_user) {
- IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __func__);
if (qos_user->baud_rate.bits)
self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
*/
void irlap_apply_default_connection_parameters(struct irlap_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_apply_connection_parameters(struct irlap_cb *self, int now)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
} else
self->fast_RR = FALSE;
- IRDA_DEBUG(3, "%s(), timeout=%d (%ld)\n", __FUNCTION__, timeout, jiffies);
+ IRDA_DEBUG(3, "%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies);
#endif /* CONFIG_IRDA_FAST_RR */
if (timeout == 0)
if (!self || self->magic != LAP_MAGIC)
return;
- IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __FUNCTION__,
+ IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __func__,
irlap_event[event], irlap_state[self->state]);
ret = (*state[self->state])(self, event, skb, info);
* try to disconnect link if we send any data frames, since
* that will change the state away form XMIT
*/
- IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__,
skb_queue_len(&self->txq));
if (!skb_queue_empty(&self->txq)) {
* media busy in irlap_connect_request() and
* postpone the event... - Jean II */
IRDA_DEBUG(0, "%s(), CONNECT_REQUEST: media busy!\n",
- __FUNCTION__);
+ __func__);
/* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
irlap_connect_indication(self, skb);
} else {
IRDA_DEBUG(0, "%s(), SNRM frame does not "
- "contain an I field!\n", __FUNCTION__);
+ "contain an I field!\n", __func__);
}
break;
case DISCOVERY_REQUEST:
if (self->media_busy) {
IRDA_DEBUG(1, "%s(), DISCOVERY_REQUEST: media busy!\n",
- __FUNCTION__);
+ __func__);
/* irlap->log.condition = MEDIA_BUSY; */
/* This will make IrLMP try again */
* those cases...
* Jean II
*/
- IRDA_DEBUG(1, "%s(), Receiving final discovery request, missed the discovery slots :-(\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Receiving final discovery request, missed the discovery slots :-(\n", __func__);
/* Last discovery request -> in the log */
irlap_discovery_indication(self, info->discovery);
/* Only accept broadcast frames in NDM mode */
if (info->caddr != CBROADCAST) {
IRDA_DEBUG(0, "%s(), not a broadcast frame!\n",
- __FUNCTION__);
+ __func__);
} else
irlap_unitdata_indication(self, skb);
break;
irlap_send_test_frame(self, CBROADCAST, info->daddr, skb);
break;
case RECV_TEST_RSP:
- IRDA_DEBUG(0, "%s() not implemented!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() not implemented!\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
irlap_event[event]);
ret = -1;
IRDA_ASSERT(info != NULL, return -1;);
IRDA_ASSERT(info->discovery != NULL, return -1;);
- IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__,
+ IRDA_DEBUG(4, "%s(), daddr=%08x\n", __func__,
info->discovery->data.daddr);
if (!self->discovery_log) {
IRDA_WARNING("%s: discovery log is gone! "
"maybe the discovery timeout has been set"
- " too short?\n", __FUNCTION__);
+ " too short?\n", __func__);
break;
}
hashbin_insert(self->discovery_log,
IRDA_ASSERT(info != NULL, return -1;);
- IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __FUNCTION__, info->s);
+ IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __func__, info->s);
/* Last discovery request ? */
if (info->s == 0xff)
*/
if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
IRDA_DEBUG(2, "%s(), device is slow to answer, "
- "waiting some more!\n", __FUNCTION__);
+ "waiting some more!\n", __func__);
irlap_start_slot_timer(self, msecs_to_jiffies(10));
self->add_wait = TRUE;
return ret;
}
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
irlap_event[event]);
ret = -1;
discovery_t *discovery_rsp;
int ret=0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
switch (event) {
case QUERY_TIMER_EXPIRED:
IRDA_DEBUG(0, "%s(), QUERY_TIMER_EXPIRED <%ld>\n",
- __FUNCTION__, jiffies);
+ __func__, jiffies);
irlap_next_state(self, LAP_NDM);
break;
case RECV_DISCOVERY_XID_CMD:
}
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__,
+ IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
event, irlap_event[event]);
ret = -1;
{
int ret = 0;
- IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]);
+ IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[ event]);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
break;
case RECV_DISCOVERY_XID_CMD:
IRDA_DEBUG(3, "%s(), event RECV_DISCOVER_XID_CMD!\n",
- __FUNCTION__);
+ __func__);
irlap_next_state(self, LAP_NDM);
break;
case DISCONNECT_REQUEST:
- IRDA_DEBUG(0, "%s(), Disconnect request!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), Disconnect request!\n", __func__);
irlap_send_dm_frame(self);
irlap_next_state( self, LAP_NDM);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__,
+ IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
event, irlap_event[event]);
ret = -1;
{
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
self->retry_count++;
break;
case RECV_SNRM_CMD:
- IRDA_DEBUG(4, "%s(), SNRM battle!\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), SNRM battle!\n", __func__);
IRDA_ASSERT(skb != NULL, return 0;);
IRDA_ASSERT(info != NULL, return 0;);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__,
+ IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
event, irlap_event[event]);
ret = -1;
static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event,
struct sk_buff *skb, struct irlap_info *info)
{
- IRDA_DEBUG( 0, "%s(), Unknown event\n", __FUNCTION__);
+ IRDA_DEBUG( 0, "%s(), Unknown event\n", __func__);
return -1;
}
*/
if((!nextfit) && (skb->len > self->bytes_left)) {
IRDA_DEBUG(0, "%s(), Not allowed to transmit"
- " more bytes!\n", __FUNCTION__);
+ " more bytes!\n", __func__);
/* Requeue the skb */
skb_queue_head(&self->txq, skb_get(skb));
/*
#endif /* CONFIG_IRDA_FAST_RR */
} else {
IRDA_DEBUG(4, "%s(), Unable to send! remote busy?\n",
- __FUNCTION__);
+ __func__);
skb_queue_head(&self->txq, skb_get(skb));
/*
break;
case POLL_TIMER_EXPIRED:
IRDA_DEBUG(3, "%s(), POLL_TIMER_EXPIRED <%ld>\n",
- __FUNCTION__, jiffies);
+ __func__, jiffies);
irlap_send_rr_frame(self, CMD_FRAME);
/* Return to NRM properly - Jean II */
self->window = self->window_size;
break;
default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n",
- __FUNCTION__, irlap_event[event]);
+ __func__, irlap_event[event]);
ret = -EINVAL;
break;
{
int ret = 0;
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
}
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d\n", __FUNCTION__, event);
+ IRDA_DEBUG(1, "%s(), Unknown event %d\n", __func__, event);
ret = -1;
break;
} else {
IRDA_DEBUG(4,
"%s(), missing or duplicate frame!\n",
- __FUNCTION__);
+ __func__);
/* Update Nr received */
irlap_update_nr_received(self, info->nr);
(nr_status == NR_UNEXPECTED))
{
IRDA_DEBUG(4, "%s(), unexpected nr and ns!\n",
- __FUNCTION__);
+ __func__);
if (info->pf) {
/* Resend rejected frames */
irlap_resend_rejected_frames(self, CMD_FRAME);
}
break;
}
- IRDA_DEBUG(1, "%s(), Not implemented!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Not implemented!\n", __func__);
IRDA_DEBUG(1, "%s(), event=%s, ns_status=%d, nr_status=%d\n",
- __FUNCTION__, irlap_event[event], ns_status, nr_status);
+ __func__, irlap_event[event], ns_status, nr_status);
break;
case RECV_UI_FRAME:
/* Poll bit cleared? */
del_timer(&self->final_timer);
irlap_data_indication(self, skb, TRUE);
irlap_next_state(self, LAP_XMIT_P);
- IRDA_DEBUG(1, "%s: RECV_UI_FRAME: next state %s\n", __FUNCTION__, irlap_state[self->state]);
+ IRDA_DEBUG(1, "%s: RECV_UI_FRAME: next state %s\n", __func__, irlap_state[self->state]);
irlap_start_poll_timer(self, self->poll_timeout);
}
break;
irlap_next_state(self, LAP_NRM_P);
} else if (ret == NR_INVALID) {
IRDA_DEBUG(1, "%s(), Received RR with "
- "invalid nr !\n", __FUNCTION__);
+ "invalid nr !\n", __func__);
irlap_next_state(self, LAP_RESET_WAIT);
irlap_start_final_timer(self, 2 * self->final_timeout);
break;
case RECV_RD_RSP:
- IRDA_DEBUG(1, "%s(), RECV_RD_RSP\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), RECV_RD_RSP\n", __func__);
irlap_flush_all_queues(self);
irlap_next_state(self, LAP_XMIT_P);
break;
default:
IRDA_DEBUG(1, "%s(), Unknown event %s\n",
- __FUNCTION__, irlap_event[event]);
+ __func__, irlap_event[event]);
ret = -1;
break;
{
int ret = 0;
- IRDA_DEBUG(3, "%s(), event = %s\n", __FUNCTION__, irlap_event[event]);
+ IRDA_DEBUG(3, "%s(), event = %s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
irlap_next_state( self, LAP_PCLOSE);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
irlap_event[event]);
ret = -1;
{
int ret = 0;
- IRDA_DEBUG(3, "%s(), event = %s\n", __FUNCTION__, irlap_event[event]);
+ IRDA_DEBUG(3, "%s(), event = %s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
* state
*/
if (!info) {
- IRDA_DEBUG(3, "%s(), RECV_SNRM_CMD\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s(), RECV_SNRM_CMD\n", __func__);
irlap_initiate_connection_state(self);
irlap_wait_min_turn_around(self, &self->qos_tx);
irlap_send_ua_response_frame(self, &self->qos_rx);
} else {
IRDA_DEBUG(0,
"%s(), SNRM frame contained an I field!\n",
- __FUNCTION__);
+ __func__);
}
break;
default:
IRDA_DEBUG(1, "%s(), Unknown event %s\n",
- __FUNCTION__, irlap_event[event]);
+ __func__, irlap_event[event]);
ret = -1;
break;
{
int ret = 0;
- IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]);
+ IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -ENODEV;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
*/
if((!nextfit) && (skb->len > self->bytes_left)) {
IRDA_DEBUG(0, "%s(), Not allowed to transmit"
- " more bytes!\n", __FUNCTION__);
+ " more bytes!\n", __func__);
/* Requeue the skb */
skb_queue_head(&self->txq, skb_get(skb));
ret = -EPROTO;
}
} else {
- IRDA_DEBUG(2, "%s(), Unable to send!\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), Unable to send!\n", __func__);
skb_queue_head(&self->txq, skb_get(skb));
ret = -EPROTO;
}
* when we return... - Jean II */
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
irlap_event[event]);
ret = -EINVAL;
int nr_status;
int ret = 0;
- IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]);
+ IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[ event]);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
case RECV_I_CMD: /* Optimize for the common case */
/* FIXME: must check for remote_busy below */
IRDA_DEBUG(4, "%s(), event=%s nr=%d, vs=%d, ns=%d, "
- "vr=%d, pf=%d\n", __FUNCTION__,
+ "vr=%d, pf=%d\n", __func__,
irlap_event[event], info->nr,
self->vs, info->ns, self->vr, info->pf);
irlap_next_state(self, LAP_NRM_S);
} else {
IRDA_DEBUG(1, "%s(), invalid nr not implemented!\n",
- __FUNCTION__);
+ __func__);
}
break;
case RECV_SNRM_CMD:
/* SNRM frame is not allowed to contain an I-field */
if (!info) {
del_timer(&self->wd_timer);
- IRDA_DEBUG(1, "%s(), received SNRM cmd\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), received SNRM cmd\n", __func__);
irlap_next_state(self, LAP_RESET_CHECK);
irlap_reset_indication(self);
} else {
IRDA_DEBUG(0,
"%s(), SNRM frame contained an I-field!\n",
- __FUNCTION__);
+ __func__);
}
break;
* which explain why we use (self->N2 / 2) here !!!
* Jean II
*/
- IRDA_DEBUG(1, "%s(), retry_count = %d\n", __FUNCTION__,
+ IRDA_DEBUG(1, "%s(), retry_count = %d\n", __func__,
self->retry_count);
if (self->retry_count < (self->N2 / 2)) {
irlap_send_test_frame(self, self->caddr, info->daddr, skb);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__,
+ IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
event, irlap_event[event]);
ret = -EINVAL;
{
int ret = 0;
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -ENODEV;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
break; /* stay in SCLOSE */
}
- IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__,
+ IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
event, irlap_event[event]);
ret = -EINVAL;
{
int ret = 0;
- IRDA_DEBUG(1, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]);
+ IRDA_DEBUG(1, "%s(), event=%s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -ENODEV;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
irlap_next_state(self, LAP_SCLOSE);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__,
+ IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
event, irlap_event[event]);
ret = -EINVAL;
irlap_insert_info(self, skb);
if (unlikely(self->mode & IRDA_MODE_MONITOR)) {
- IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __FUNCTION__,
+ IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __func__,
self->netdev->name);
dev_kfree_skb(skb);
return;
/* Check if the new connection address is valid */
if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
IRDA_DEBUG(3, "%s(), invalid connection address!\n",
- __FUNCTION__);
+ __func__);
return;
}
/* Only accept if addressed directly to us */
if (info->saddr != self->saddr) {
IRDA_DEBUG(2, "%s(), not addressed to us!\n",
- __FUNCTION__);
+ __func__);
return;
}
irlap_do_event(self, RECV_SNRM_CMD, skb, info);
struct ua_frame *frame;
int ret;
- IRDA_DEBUG(2, "%s() <%ld>\n", __FUNCTION__, jiffies);
+ IRDA_DEBUG(2, "%s() <%ld>\n", __func__, jiffies);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
struct sk_buff *tx_skb = NULL;
struct disc_frame *frame;
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
__u32 bcast = BROADCAST;
__u8 *info;
- IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__,
+ IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __func__,
s, S, command);
IRDA_ASSERT(self != NULL, return;);
__u8 *discovery_info;
char *text;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
- IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+ IRDA_ERROR("%s: frame too short!\n", __func__);
return;
}
/* Make sure frame is addressed to us */
if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n",
- __FUNCTION__);
+ __func__);
return;
}
if ((discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
- IRDA_WARNING("%s: kmalloc failed!\n", __FUNCTION__);
+ IRDA_WARNING("%s: kmalloc failed!\n", __func__);
return;
}
discovery->data.saddr = self->saddr;
discovery->timestamp = jiffies;
- IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__,
+ IRDA_DEBUG(4, "%s(), daddr=%08x\n", __func__,
discovery->data.daddr);
discovery_info = skb_pull(skb, sizeof(struct xid_frame));
char *text;
if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
- IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+ IRDA_ERROR("%s: frame too short!\n", __func__);
return;
}
/* Make sure frame is addressed to us */
if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n",
- __FUNCTION__);
+ __func__);
return;
}
if((discovery_info == NULL) ||
!pskb_may_pull(skb, 3)) {
IRDA_ERROR("%s: discovery frame too short!\n",
- __FUNCTION__);
+ __func__);
return;
}
*/
discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC);
if (!discovery) {
- IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__);
+ IRDA_WARNING("%s: unable to malloc!\n", __func__);
return;
}
{
info->nr = skb->data[1] >> 5;
- IRDA_DEBUG(4, "%s(), nr=%d, %ld\n", __FUNCTION__, info->nr, jiffies);
+ IRDA_DEBUG(4, "%s(), nr=%d, %ld\n", __func__, info->nr, jiffies);
if (command)
irlap_do_event(self, RECV_RNR_CMD, skb, info);
static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info, int command)
{
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s()\n", __func__);
info->nr = skb->data[1] >> 5;
static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info, int command)
{
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s()\n", __func__);
info->nr = skb->data[1] >> 5;
static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info, int command)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
/* Check if this is a command or a response frame */
if (command)
irlap_send_i_frame( self, tx_skb, CMD_FRAME);
} else {
- IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __func__);
irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
self->window -= 1;
}
irlap_next_state(self, LAP_NRM_P);
irlap_send_i_frame(self, tx_skb, CMD_FRAME);
} else {
- IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __func__);
if (self->ack_required) {
irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
* See max_line_capacities[][] in qos.c for details. Jean II */
transmission_time -= (self->final_timeout * self->bytes_left
/ self->line_capacity);
- IRDA_DEBUG(4, "%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", __FUNCTION__, self->final_timeout, self->bytes_left, self->line_capacity, transmission_time);
+ IRDA_DEBUG(4, "%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", __func__, self->final_timeout, self->bytes_left, self->line_capacity, transmission_time);
/* We are allowed to transmit a maximum number of bytes again. */
self->bytes_left = self->line_capacity;
/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
tx_skb = skb_copy(skb, GFP_ATOMIC);
if (!tx_skb) {
- IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unable to copy\n", __func__);
return;
}
*/
while (!skb_queue_empty(&self->txq)) {
- IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), sending additional frames!\n", __func__);
if (self->window > 0) {
skb = skb_dequeue( &self->txq);
IRDA_ASSERT(skb != NULL, return;);
/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
tx_skb = skb_copy(skb, GFP_ATOMIC);
if (!tx_skb) {
- IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unable to copy\n", __func__);
return;
}
void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
__u8 caddr, int command)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info)
{
- IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG( 4, "%s()\n", __func__);
info->pf = skb->data[1] & PF_BIT; /* Final bit */
__u8 *frame;
int w, x, y, z;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(info != NULL, return;);
if (!pskb_may_pull(skb, 4)) {
- IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+ IRDA_ERROR("%s: frame too short!\n", __func__);
return;
}
{
struct test_frame *frame;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
if (!pskb_may_pull(skb, sizeof(*frame))) {
- IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+ IRDA_ERROR("%s: frame too short!\n", __func__);
return;
}
frame = (struct test_frame *) skb->data;
if (info->caddr == CBROADCAST) {
if (skb->len < sizeof(struct test_frame)) {
IRDA_DEBUG(0, "%s() test frame too short!\n",
- __FUNCTION__);
+ __func__);
return;
}
* share and non linear skbs. This should never happen, so
* we don't need to be clever about it. Jean II */
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- IRDA_ERROR("%s: can't clone shared skb!\n", __FUNCTION__);
+ IRDA_ERROR("%s: can't clone shared skb!\n", __func__);
dev_kfree_skb(skb);
return -1;
}
/* Check if frame is large enough for parsing */
if (!pskb_may_pull(skb, 2)) {
- IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+ IRDA_ERROR("%s: frame too short!\n", __func__);
dev_kfree_skb(skb);
return -1;
}
/* First we check if this frame has a valid connection address */
if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) {
IRDA_DEBUG(0, "%s(), wrong connection address!\n",
- __FUNCTION__);
+ __func__);
goto out;
}
/*
break;
default:
IRDA_WARNING("%s: Unknown S-frame %02x received!\n",
- __FUNCTION__, info.control);
+ __func__, info.control);
break;
}
goto out;
break;
default:
IRDA_WARNING("%s: Unknown frame %02x received!\n",
- __FUNCTION__, info.control);
+ __func__, info.control);
break;
}
out:
*/
int __init irlmp_init(void)
{
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
/* Initialize the irlmp structure. */
irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
if (irlmp == NULL)
/* Allocate new instance of a LSAP connection */
self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
if (self == NULL) {
- IRDA_ERROR("%s: can't allocate memory\n", __FUNCTION__);
+ IRDA_ERROR("%s: can't allocate memory\n", __func__);
return NULL;
}
*/
static void __irlmp_close_lsap(struct lsap_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
if (!lsap) {
IRDA_DEBUG(0,
"%s(), Looks like somebody has removed me already!\n",
- __FUNCTION__);
+ __func__);
return;
}
__irlmp_close_lsap(self);
*/
lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL);
if (lap == NULL) {
- IRDA_ERROR("%s: unable to kmalloc\n", __FUNCTION__);
+ IRDA_ERROR("%s: unable to kmalloc\n", __func__);
return;
}
#endif
lap->lsaps = hashbin_new(HB_LOCK);
if (lap->lsaps == NULL) {
- IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __FUNCTION__);
+ IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __func__);
kfree(lap);
return;
}
{
struct lap_cb *link;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
/* We must remove ourselves from the hashbin *first*. This ensure
* that no more LSAPs will be open on this link and no discovery
IRDA_DEBUG(2,
"%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
- __FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr);
+ __func__, self->slsap_sel, dlsap_sel, saddr, daddr);
if (test_bit(0, &self->connected)) {
ret = -EISCONN;
if (daddr != DEV_ADDR_ANY)
discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
else {
- IRDA_DEBUG(2, "%s(), no daddr\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), no daddr\n", __func__);
discovery = (discovery_t *)
hashbin_get_first(irlmp->cachelog);
}
}
lap = hashbin_lock_find(irlmp->links, saddr, NULL);
if (lap == NULL) {
- IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __func__);
ret = -EHOSTUNREACH;
goto err;
}
* disconnected yet (waiting for timeout in LAP).
* Maybe we could give LAP a bit of help in this case.
*/
- IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __func__);
ret = -EAGAIN;
goto err;
}
/* LAP is already connected to a different node, and LAP
* can only talk to one node at a time */
- IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __func__);
ret = -EBUSY;
goto err;
}
IRDA_ASSERT(self->lap != NULL, return;);
IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __FUNCTION__, self->slsap_sel, self->dlsap_sel);
+ __func__, self->slsap_sel, self->dlsap_sel);
/* Note : self->lap is set in irlmp_link_data_indication(),
* (case CONNECT_CMD:) because we have no way to set it here.
* in the state machine itself. Jean II */
IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __FUNCTION__, self->slsap_sel, self->dlsap_sel);
+ __func__, self->slsap_sel, self->dlsap_sel);
/* Make room for MUX control header (3 bytes) */
IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
int lap_header_size;
int max_seg_size;
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(self != NULL, return;);
max_header_size = LMP_HEADER + lap_header_size;
IRDA_DEBUG(2, "%s(), max_header_size=%d\n",
- __FUNCTION__, max_header_size);
+ __func__, max_header_size);
/* Hide LMP_CONTROL_HEADER header from layer above */
skb_pull(skb, LMP_CONTROL_HEADER);
struct lsap_cb *new;
unsigned long flags;
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) ||
(orig->lap == NULL)) {
IRDA_DEBUG(0, "%s(), invalid LSAP (wrong state)\n",
- __FUNCTION__);
+ __func__);
spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
flags);
return NULL;
/* Allocate a new instance */
new = kmemdup(orig, sizeof(*new), GFP_ATOMIC);
if (!new) {
- IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__);
spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
flags);
return NULL;
* and us that might mess up the hashbins below. This fixes it.
* Jean II */
if (! test_and_clear_bit(0, &self->connected)) {
- IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__);
dev_kfree_skb(userdata);
return -1;
}
{
struct lsap_cb *lsap;
- IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]);
+ IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __FUNCTION__, self->slsap_sel, self->dlsap_sel);
+ __func__, self->slsap_sel, self->dlsap_sel);
/* Already disconnected ?
* There is a race condition between irlmp_disconnect_request()
* and us that might mess up the hashbins below. This fixes it.
* Jean II */
if (! test_and_clear_bit(0, &self->connected)) {
- IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__);
return;
}
self->notify.disconnect_indication(self->notify.instance,
self, reason, skb);
} else {
- IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), no handler\n", __func__);
}
}
/* Make sure the value is sane */
if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
IRDA_WARNING("%s: invalid value for number of slots!\n",
- __FUNCTION__);
+ __func__);
nslots = sysctl_discovery_slots = 8;
}
int number; /* Number of nodes in the log */
int i;
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
/* Check if client wants or not partial/selective log (optimisation) */
if (!client->disco_callback)
irlmp_client_t *client;
irlmp_client_t *client_next;
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
IRDA_ASSERT(log != NULL, return;);
irlmp_client_t *client_next;
int i;
- IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(3, "%s()\n", __func__);
IRDA_ASSERT(expiries != NULL, return;);
*/
discovery_t *irlmp_get_discovery_response(void)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(irlmp != NULL, return NULL;);
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(userdata != NULL, return -1;);
*/
void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
struct sk_buff *clone_skb;
struct lap_cb *lap;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(userdata != NULL, return -1;);
#ifdef CONFIG_IRDA_ULTRA
void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
curr->notify.status_indication(curr->notify.instance,
link, lock);
else
- IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), no handler\n", __func__);
curr = next;
}
/* Get the number of lsap. That's the only safe way to know
* that we have looped around... - Jean II */
lsap_todo = HASHBIN_GET_SIZE(self->lsaps);
- IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __FUNCTION__, lsap_todo);
+ IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __func__, lsap_todo);
/* Poll lsap in order until the queue is full or until we
* tried them all.
/* Uh-oh... Paranoia */
if(curr == NULL)
break;
- IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __FUNCTION__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
+ IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __func__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
/* Inform lsap user that it can send one more packet. */
if (curr->notify.flow_indication != NULL)
curr->notify.flow_indication(curr->notify.instance,
curr, flow);
else
- IRDA_DEBUG(1, "%s(), no handler\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), no handler\n", __func__);
}
}
*/
service = kmalloc(16, GFP_ATOMIC);
if (!service) {
- IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__);
return NULL;
}
{
irlmp_service_t *service;
- IRDA_DEBUG(4, "%s(), hints = %04x\n", __FUNCTION__, hints);
+ IRDA_DEBUG(4, "%s(), hints = %04x\n", __func__, hints);
/* Make a new registration */
service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
if (!service) {
- IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__);
return NULL;
}
service->hints.word = hints;
irlmp_service_t *service;
unsigned long flags;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
if (!handle)
return -1;
/* Caller may call with invalid handle (it's legal) - Jean II */
service = hashbin_lock_find(irlmp->services, (long) handle, NULL);
if (!service) {
- IRDA_DEBUG(1, "%s(), Unknown service!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Unknown service!\n", __func__);
return -1;
}
{
irlmp_client_t *client;
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
IRDA_ASSERT(irlmp != NULL, return NULL;);
/* Make a new registration */
client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
if (!client) {
- IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
+ IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __func__);
return NULL;
}
client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
if (!client) {
- IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__);
return -1;
}
{
struct irlmp_client *client;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
if (!handle)
return -1;
/* Caller may call with invalid handle (it's legal) - Jean II */
client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
if (!client) {
- IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__);
return -1;
}
- IRDA_DEBUG(4, "%s(), removing client!\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), removing client!\n", __func__);
hashbin_remove_this(irlmp->clients, (irda_queue_t *) client);
kfree(client);
IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
#ifdef CONFIG_IRDA_ULTRA
/* Accept all bindings to the connectionless LSAP */
/* Make sure we terminate the loop */
if (wrapped++) {
IRDA_ERROR("%s: no more free LSAPs !\n",
- __FUNCTION__);
+ __func__);
return 0;
}
}
/* Got it ! */
lsap_sel = irlmp->last_lsap_sel;
IRDA_DEBUG(4, "%s(), found free lsap_sel=%02x\n",
- __FUNCTION__, lsap_sel);
+ __func__, lsap_sel);
return lsap_sel;
}
switch (lap_reason) {
case LAP_DISC_INDICATION: /* Received a disconnect request from peer */
- IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __FUNCTION__);
+ IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __func__);
reason = LM_USER_REQUEST;
break;
case LAP_NO_RESPONSE: /* To many retransmits without response */
- IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __FUNCTION__);
+ IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __func__);
reason = LM_LAP_DISCONNECT;
break;
case LAP_RESET_INDICATION:
- IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __FUNCTION__);
+ IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __func__);
reason = LM_LAP_RESET;
break;
case LAP_FOUND_NONE:
case LAP_MEDIA_BUSY:
case LAP_PRIMARY_CONFLICT:
- IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __func__);
reason = LM_CONNECT_FAILURE;
break;
default:
IRDA_DEBUG(1, "%s(), Unknow IrLAP disconnect reason %d!\n",
- __FUNCTION__, lap_reason);
+ __func__, lap_reason);
reason = LM_LAP_DISCONNECT;
break;
}
IRLMP_STATE state)
{
/*
- IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __FUNCTION__, irlmp_state[state]);
+ IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __func__, irlmp_state[state]);
*/
self->lap_state = state;
}
{
/*
IRDA_ASSERT(self != NULL, return;);
- IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __FUNCTION__, irlsap_state[state]);
+ IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]);
*/
self->lsap_state = state;
}
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",
- __FUNCTION__, irlmp_event[event], irlsap_state[ self->lsap_state]);
+ __func__, irlmp_event[event], irlsap_state[ self->lsap_state]);
return (*lsap_state[self->lsap_state]) (self, event, skb);
}
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
- IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __FUNCTION__,
+ IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __func__,
irlmp_event[event],
irlmp_state[self->lap_state]);
void irlmp_discovery_timer_expired(void *data)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
/* We always cleanup the log (active & passive discovery) */
irlmp_do_expiry();
{
struct lsap_cb *self = (struct lsap_cb *) data;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
{
struct lap_cb *self = (struct lap_cb *) data;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self->irlap != NULL, return;);
switch (event) {
irlap_connect_response(self->irlap, skb);
break;
case LM_LAP_CONNECT_REQUEST:
- IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __func__);
irlmp_next_lap_state(self, LAP_U_CONNECT);
break;
case LM_LAP_DISCONNECT_INDICATION:
IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n",
- __FUNCTION__);
+ __func__);
irlmp_next_lap_state(self, LAP_STANDBY);
break;
default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n",
- __FUNCTION__, irlmp_event[event]);
+ __func__, irlmp_event[event]);
break;
}
}
static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s(), event=%s\n", __FUNCTION__, irlmp_event[event]);
+ IRDA_DEBUG(2, "%s(), event=%s\n", __func__, irlmp_event[event]);
switch (event) {
case LM_LAP_CONNECT_INDICATION:
* the lsaps may already have gone. This avoid getting stuck
* forever in LAP_ACTIVE state - Jean II */
if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
- IRDA_DEBUG(0, "%s() NO LSAPs !\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() NO LSAPs !\n", __func__);
irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
}
break;
* the lsaps may already have gone. This avoid getting stuck
* forever in LAP_ACTIVE state - Jean II */
if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
- IRDA_DEBUG(0, "%s() NO LSAPs !\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() NO LSAPs !\n", __func__);
irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
}
break;
case LM_LAP_DISCONNECT_INDICATION:
- IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n", __func__);
irlmp_next_lap_state(self, LAP_STANDBY);
/* Send disconnect event to all LSAPs using this link */
LM_LAP_DISCONNECT_INDICATION);
break;
case LM_LAP_DISCONNECT_REQUEST:
- IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n", __func__);
/* One of the LSAP did timeout or was closed, if it was
* the last one, try to get out of here - Jean II */
break;
default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n",
- __FUNCTION__, irlmp_event[event]);
+ __func__, irlmp_event[event]);
break;
}
}
static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
switch (event) {
case LM_LAP_CONNECT_REQUEST:
- IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __func__);
/*
* IrLAP may have a pending disconnect. We tried to close
break;
default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n",
- __FUNCTION__, irlmp_event[event]);
+ __func__, irlmp_event[event]);
break;
}
}
{
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
break;
#endif /* CONFIG_IRDA_ULTRA */
case LM_CONNECT_REQUEST:
- IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __func__);
if (self->conn_skb) {
IRDA_WARNING("%s: busy with another request!\n",
- __FUNCTION__);
+ __func__);
return -EBUSY;
}
/* Don't forget to refcount it (see irlmp_connect_request()) */
case LM_CONNECT_INDICATION:
if (self->conn_skb) {
IRDA_WARNING("%s: busy with another request!\n",
- __FUNCTION__);
+ __func__);
return -EBUSY;
}
/* Don't forget to refcount it (see irlap_driver_rcv()) */
break;
default:
IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n",
- __FUNCTION__, irlmp_event[event], self->slsap_sel);
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
struct lsap_cb *lsap;
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
case LM_WATCHDOG_TIMEOUT:
/* May happen, who knows...
* Jean II */
- IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
/* Disconnect, get out... - Jean II */
self->lap = NULL;
/* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
* are *not* yet bound to the IrLAP link. Jean II */
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __FUNCTION__, irlmp_event[event], self->slsap_sel);
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
struct sk_buff *tx_skb;
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
break;
case LM_CONNECT_RESPONSE:
IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
- "no indication issued yet\n", __FUNCTION__);
+ "no indication issued yet\n", __func__);
/* Keep state */
break;
case LM_DISCONNECT_REQUEST:
IRDA_DEBUG(0, "%s(), LM_DISCONNECT_REQUEST, "
- "not yet bound to IrLAP connection\n", __FUNCTION__);
+ "not yet bound to IrLAP connection\n", __func__);
/* Keep state */
break;
case LM_LAP_CONNECT_CONFIRM:
- IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __func__);
irlmp_next_lsap_state(self, LSAP_CONNECT);
tx_skb = self->conn_skb;
/* Will happen in some rare cases because of a race condition.
* Just make sure we don't stay there forever...
* Jean II */
- IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
/* Go back to disconnected mode, keep the socket waiting */
self->lap = NULL;
/* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
* are *not* yet bound to the IrLAP link. Jean II */
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __FUNCTION__, irlmp_event[event], self->slsap_sel);
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
LM_REASON reason;
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
break;
case LM_CONNECT_REQUEST:
IRDA_DEBUG(0, "%s(), LM_CONNECT_REQUEST, "
- "error, LSAP already connected\n", __FUNCTION__);
+ "error, LSAP already connected\n", __func__);
/* Keep state */
break;
case LM_CONNECT_RESPONSE:
IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
- "error, LSAP already connected\n", __FUNCTION__);
+ "error, LSAP already connected\n", __func__);
/* Keep state */
break;
case LM_DISCONNECT_REQUEST:
/* Try to close the LAP connection if its still there */
if (self->lap) {
IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",
- __FUNCTION__);
+ __func__);
irlmp_do_lap_event(self->lap,
LM_LAP_DISCONNECT_REQUEST,
NULL);
reason = skb->data[3];
/* Try to close the LAP connection */
- IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
irlmp_disconnect_indication(self, reason, skb);
break;
default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __FUNCTION__, irlmp_event[event], self->slsap_sel);
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
switch (event) {
case LM_CONNECT_CONFIRM:
reason = skb->data[3];
/* Try to close the LAP connection */
- IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
irlmp_disconnect_indication(self, reason, skb);
irlmp_disconnect_indication(self, reason, skb);
break;
case LM_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
IRDA_ASSERT(self->lap != NULL, return -1;);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
break;
default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __FUNCTION__, irlmp_event[event], self->slsap_sel);
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
LM_REASON reason;
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(irlmp != NULL, return -1;);
irlmp_next_lsap_state(self, LSAP_SETUP);
break;
case LM_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n", __func__);
IRDA_ASSERT(self->lap != NULL, return -1;);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
break;
default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __FUNCTION__, irlmp_event[event], self->slsap_sel);
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
skb->data[1] = slsap;
if (expedited) {
- IRDA_DEBUG(4, "%s(), sending expedited data\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), sending expedited data\n", __func__);
irlap_data_request(self->irlap, skb, TRUE);
} else
irlap_data_request(self->irlap, skb, FALSE);
{
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
__u8 dlsap_sel; /* Destination LSAP address */
__u8 *fp;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
IRDA_DEBUG(3, "%s(), incoming connection, "
"source LSAP=%d, dest LSAP=%d\n",
- __FUNCTION__, slsap_sel, dlsap_sel);
+ __func__, slsap_sel, dlsap_sel);
/* Try to find LSAP among the unconnected LSAPs */
lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD,
/* Maybe LSAP was already connected, so try one more time */
if (!lsap) {
- IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __func__);
lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
self->lsaps);
}
if (lsap == NULL) {
IRDA_DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
IRDA_DEBUG(2, "%s(), slsap_sel = %02x, dlsap_sel = %02x\n",
- __FUNCTION__, slsap_sel, dlsap_sel);
+ __func__, slsap_sel, dlsap_sel);
if (fp[0] & CONTROL_BIT) {
IRDA_DEBUG(2, "%s(), received control frame %02x\n",
- __FUNCTION__, fp[2]);
+ __func__, fp[2]);
} else {
- IRDA_DEBUG(2, "%s(), received data frame\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), received data frame\n", __func__);
}
return;
}
break;
case DISCONNECT:
IRDA_DEBUG(4, "%s(), Disconnect indication!\n",
- __FUNCTION__);
+ __func__);
irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION,
skb);
break;
break;
default:
IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n",
- __FUNCTION__, fp[2]);
+ __func__, fp[2]);
break;
}
} else if (unreliable) {
__u8 *fp;
unsigned long flags;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
if (pid & 0x80) {
IRDA_DEBUG(0, "%s(), extension in PID not supp!\n",
- __FUNCTION__);
+ __func__);
return;
}
/* Check if frame is addressed to the connectionless LSAP */
if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
- IRDA_DEBUG(0, "%s(), dropping frame!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), dropping frame!\n", __func__);
return;
}
if (lsap)
irlmp_connless_data_indication(lsap, skb);
else {
- IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __func__);
}
}
#endif /* CONFIG_IRDA_ULTRA */
LAP_REASON reason,
struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
IRDA_ASSERT(lap != NULL, return;);
IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
__u32 daddr, struct qos_info *qos,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
/* Copy QoS settings for this session */
self->qos = qos;
void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
*/
void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
{
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
{
int ret = 0;
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s()\n", __func__);
/* Lower layer of the stack */
irlmp_init();
/* All error messages (will show up in the normal logs) */
#define DERROR(dbg, format, args...) \
{if(DEBUG_##dbg) \
- printk(KERN_INFO "irnet: %s(): " format, __FUNCTION__ , ##args);}
+ printk(KERN_INFO "irnet: %s(): " format, __func__ , ##args);}
/* Normal debug message (will show up in /var/log/debug) */
#define DEBUG(dbg, format, args...) \
{if(DEBUG_##dbg) \
- printk(KERN_DEBUG "irnet: %s(): " format, __FUNCTION__ , ##args);}
+ printk(KERN_DEBUG "irnet: %s(): " format, __func__ , ##args);}
/* Entering a function (trace) */
#define DENTER(dbg, format, args...) \
{if(DEBUG_##dbg) \
- printk(KERN_DEBUG "irnet: -> %s" format, __FUNCTION__ , ##args);}
+ printk(KERN_DEBUG "irnet: -> %s" format, __func__ , ##args);}
/* Entering and exiting a function in one go (trace) */
#define DPASS(dbg, format, args...) \
{if(DEBUG_##dbg) \
- printk(KERN_DEBUG "irnet: <>%s" format, __FUNCTION__ , ##args);}
+ printk(KERN_DEBUG "irnet: <>%s" format, __func__ , ##args);}
/* Exiting a function (trace) */
#define DEXIT(dbg, format, args...) \
{if(DEBUG_##dbg) \
- printk(KERN_DEBUG "irnet: <-%s()" format, __FUNCTION__ , ##args);}
+ printk(KERN_DEBUG "irnet: <-%s()" format, __func__ , ##args);}
/* Exit a function with debug */
#define DRETURN(ret, dbg, args...) \
ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]);
- IRDA_DEBUG(5, "%s(): Looking for %s\n", __FUNCTION__, ifname);
+ IRDA_DEBUG(5, "%s(): Looking for %s\n", __func__, ifname);
return dev_get_by_name(net, ifname);
}
mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]);
- IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __FUNCTION__, mode);
+ IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __func__, mode);
dev = ifname_to_netdev(&init_net, info);
if (!dev)
static void enqueue_first(irda_queue_t **queue, irda_queue_t* element)
{
- IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG( 4, "%s()\n", __func__);
/*
* Check if queue is empty.
unsigned long flags = 0;
int bin;
- IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG( 4, "%s()\n", __func__);
IRDA_ASSERT( hashbin != NULL, return;);
IRDA_ASSERT( hashbin->magic == HB_MAGIC, return;);
unsigned long flags = 0;
irda_queue_t* entry;
- IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG( 4, "%s()\n", __func__);
IRDA_ASSERT( hashbin != NULL, return NULL;);
IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
int bin;
long hashv;
- IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG( 4, "%s()\n", __func__);
IRDA_ASSERT( hashbin != NULL, return NULL;);
IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
irttp->tsaps = hashbin_new(HB_LOCK);
if (!irttp->tsaps) {
IRDA_ERROR("%s: can't allocate IrTTP hashbin!\n",
- __FUNCTION__);
+ __func__);
kfree(irttp);
return -ENOMEM;
}
if (!self || self->magic != TTP_TSAP_MAGIC)
return;
- IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(4, "%s(instance=%p)\n", __func__, self);
/* Try to make some progress, especially on Tx side - Jean II */
irttp_run_rx_queue(self);
{
struct sk_buff* skb;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
IRDA_ASSERT(self != NULL, return NULL;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
- IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __func__,
self->rx_sdu_size);
skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
IRDA_DEBUG(2,
"%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n",
- __FUNCTION__, n, self->rx_sdu_size, self->rx_max_sdu_size);
+ __func__, n, self->rx_sdu_size, self->rx_max_sdu_size);
/* Note : irttp_run_rx_queue() calculate self->rx_sdu_size
* by summing the size of all fragments, so we should always
* have n == self->rx_sdu_size, except in cases where we
struct sk_buff *frag;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
* Split frame into a number of segments
*/
while (skb->len > self->max_seg_size) {
- IRDA_DEBUG(2, "%s(), fragmenting ...\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), fragmenting ...\n", __func__);
/* Make new segment */
frag = alloc_skb(self->max_seg_size+self->max_header_size,
skb_queue_tail(&self->tx_queue, frag);
}
/* Queue what is left of the original skb */
- IRDA_DEBUG(2, "%s(), queuing last segment\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), queuing last segment\n", __func__);
frame = skb_push(skb, TTP_HEADER);
frame[0] = 0x00; /* Clear more bit */
else
self->tx_max_sdu_size = param->pv.i;
- IRDA_DEBUG(1, "%s(), MaxSduSize=%d\n", __FUNCTION__, param->pv.i);
+ IRDA_DEBUG(1, "%s(), MaxSduSize=%d\n", __func__, param->pv.i);
return 0;
}
* JeanII */
if((stsap_sel != LSAP_ANY) &&
((stsap_sel < 0x01) || (stsap_sel >= 0x70))) {
- IRDA_DEBUG(0, "%s(), invalid tsap!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), invalid tsap!\n", __func__);
return NULL;
}
self = kzalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
if (self == NULL) {
- IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __func__);
return NULL;
}
*/
lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
if (lsap == NULL) {
- IRDA_WARNING("%s: unable to allocate LSAP!!\n", __FUNCTION__);
+ IRDA_WARNING("%s: unable to allocate LSAP!!\n", __func__);
return NULL;
}
* the stsap_sel we have might not be valid anymore
*/
self->stsap_sel = lsap->slsap_sel;
- IRDA_DEBUG(4, "%s(), stsap_sel=%02x\n", __FUNCTION__, self->stsap_sel);
+ IRDA_DEBUG(4, "%s(), stsap_sel=%02x\n", __func__, self->stsap_sel);
self->notify = *notify;
self->lsap = lsap;
{
struct tsap_cb *tsap;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
/* Check if disconnect is not pending */
if (!test_bit(0, &self->disconnect_pend)) {
IRDA_WARNING("%s: TSAP still connected!\n",
- __FUNCTION__);
+ __func__);
irttp_disconnect_request(self, NULL, P_NORMAL);
}
self->close_pend = TRUE;
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
/* Check that nothing bad happens */
if ((skb->len == 0) || (!self->connected)) {
IRDA_DEBUG(1, "%s(), No data, or not connected\n",
- __FUNCTION__);
+ __func__);
goto err;
}
if (skb->len > self->max_seg_size) {
IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n",
- __FUNCTION__);
+ __func__);
goto err;
}
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
- IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__,
skb_queue_len(&self->tx_queue));
/* Check that nothing bad happens */
if ((skb->len == 0) || (!self->connected)) {
- IRDA_WARNING("%s: No data, or not connected\n", __FUNCTION__);
+ IRDA_WARNING("%s: No data, or not connected\n", __func__);
ret = -ENOTCONN;
goto err;
}
*/
if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
IRDA_ERROR("%s: SAR disabled, and data is too large for IrLAP!\n",
- __FUNCTION__);
+ __func__);
ret = -EMSGSIZE;
goto err;
}
(skb->len > self->tx_max_sdu_size))
{
IRDA_ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
- __FUNCTION__);
+ __func__);
ret = -EMSGSIZE;
goto err;
}
int n;
IRDA_DEBUG(2, "%s() : send_credit = %d, queue_len = %d\n",
- __FUNCTION__,
+ __func__,
self->send_credit, skb_queue_len(&self->tx_queue));
/* Get exclusive access to the tx queue, otherwise don't touch it */
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n",
- __FUNCTION__,
+ __func__,
self->send_credit, self->avail_credit, self->remote_credit);
/* Give credit to peer */
struct tsap_cb *self;
int err;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
self = (struct tsap_cb *) instance;
{
struct tsap_cb *self;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
self = (struct tsap_cb *) instance;
self->notify.status_indication(self->notify.instance,
link, lock);
else
- IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), no handler\n", __func__);
}
/*
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
- IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self);
+ IRDA_DEBUG(4, "%s(instance=%p)\n", __func__, self);
/* We are "polled" directly from LAP, and the LAP want to fill
* its Tx window. We want to do our best to send it data, so that
*/
void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow)
{
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
switch (flow) {
case FLOW_STOP:
- IRDA_DEBUG(1, "%s(), flow stop\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), flow stop\n", __func__);
self->rx_sdu_busy = TRUE;
break;
case FLOW_START:
- IRDA_DEBUG(1, "%s(), flow start\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), flow start\n", __func__);
self->rx_sdu_busy = FALSE;
/* Client say he can accept more data, try to free our
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __func__);
}
}
EXPORT_SYMBOL(irttp_flow_request);
__u8 *frame;
__u8 n;
- IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __FUNCTION__, max_sdu_size);
+ IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __func__, max_sdu_size);
IRDA_ASSERT(self != NULL, return -EBADR;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
__u8 plen;
__u8 n;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
self = (struct tsap_cb *) instance;
n = skb->data[0] & 0x7f;
- IRDA_DEBUG(4, "%s(), Initial send_credit=%d\n", __FUNCTION__, n);
+ IRDA_DEBUG(4, "%s(), Initial send_credit=%d\n", __func__, n);
self->send_credit = n;
self->tx_max_sdu_size = 0;
/* Any errors in the parameter list? */
if (ret < 0) {
IRDA_WARNING("%s: error extracting parameters\n",
- __FUNCTION__);
+ __func__);
dev_kfree_skb(skb);
/* Do not accept this connection attempt */
skb_pull(skb, IRDA_MIN(skb->len, plen+1));
}
- IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", __FUNCTION__,
+ IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", __func__,
self->send_credit, self->avail_credit, self->remote_credit);
- IRDA_DEBUG(2, "%s(), MaxSduSize=%d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), MaxSduSize=%d\n", __func__,
self->tx_max_sdu_size);
if (self->notify.connect_confirm) {
self->max_seg_size = max_seg_size - TTP_HEADER;
self->max_header_size = max_header_size+TTP_HEADER;
- IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __FUNCTION__, self->stsap_sel);
+ IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __func__, self->stsap_sel);
/* Need to update dtsap_sel if its equal to LSAP_ANY */
self->dtsap_sel = lsap->dlsap_sel;
/* Any errors in the parameter list? */
if (ret < 0) {
IRDA_WARNING("%s: error extracting parameters\n",
- __FUNCTION__);
+ __func__);
dev_kfree_skb(skb);
/* Do not accept this connection attempt */
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
- IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __FUNCTION__,
+ IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __func__,
self->stsap_sel);
/* Any userdata supplied? */
struct tsap_cb *new;
unsigned long flags;
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s()\n", __func__);
/* Protect our access to the old tsap instance */
spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags);
/* Find the old instance */
if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) {
- IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __func__);
spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
return NULL;
}
/* Allocate a new instance */
new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
if (!new) {
- IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__);
spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
return NULL;
}
/* Try to dup the LSAP (may fail if we were too slow) */
new->lsap = irlmp_dup(orig->lsap, new);
if (!new->lsap) {
- IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
kfree(new);
return NULL;
}
/* Already disconnected? */
if (!self->connected) {
- IRDA_DEBUG(4, "%s(), already disconnected!\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s(), already disconnected!\n", __func__);
if (userdata)
dev_kfree_skb(userdata);
return -1;
* Jean II */
if(test_and_set_bit(0, &self->disconnect_pend)) {
IRDA_DEBUG(0, "%s(), disconnect already pending\n",
- __FUNCTION__);
+ __func__);
if (userdata)
dev_kfree_skb(userdata);
* disconnecting right now since the data will
* not have any usable connection to be sent on
*/
- IRDA_DEBUG(1, "%s(): High priority!!()\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(): High priority!!()\n", __func__);
irttp_flush_queues(self);
} else if (priority == P_NORMAL) {
/*
* be sent at the LMP level (so even if the peer has its Tx queue
* full of data). - Jean II */
- IRDA_DEBUG(1, "%s(), Disconnecting ...\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Disconnecting ...\n", __func__);
self->connected = FALSE;
if (!userdata) {
{
struct tsap_cb *self;
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(4, "%s()\n", __func__);
self = (struct tsap_cb *) instance;
* give an error back
*/
if (err) {
- IRDA_DEBUG(0, "%s() requeueing skb!\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s() requeueing skb!\n", __func__);
/* Make sure we take a break */
self->rx_sdu_busy = TRUE;
struct sk_buff *skb;
int more = 0;
- IRDA_DEBUG(2, "%s() send=%d,avail=%d,remote=%d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s() send=%d,avail=%d,remote=%d\n", __func__,
self->send_credit, self->avail_credit, self->remote_credit);
/* Get exclusive access to the rx queue, otherwise don't touch it */
*/
if (self->rx_sdu_size <= self->rx_max_sdu_size) {
IRDA_DEBUG(4, "%s(), queueing frag\n",
- __FUNCTION__);
+ __func__);
skb_queue_tail(&self->rx_fragments, skb);
} else {
/* Free the part of the SDU that is too big */
/* Now we can deliver the reassembled skb */
irttp_do_data_indication(self, skb);
} else {
- IRDA_DEBUG(1, "%s(), Truncated frame\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), Truncated frame\n", __func__);
/* Free the part of the SDU that is too big */
dev_kfree_skb(skb);
*/
if (p.pl == 0) {
if (p.pv.i < 0xff) {
- IRDA_DEBUG(2, "%s(), using 1 byte\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), using 1 byte\n", __func__);
p.pl = 1;
} else if (p.pv.i < 0xffff) {
- IRDA_DEBUG(2, "%s(), using 2 bytes\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), using 2 bytes\n", __func__);
p.pl = 2;
} else {
- IRDA_DEBUG(2, "%s(), using 4 bytes\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s(), using 4 bytes\n", __func__);
p.pl = 4; /* Default length */
}
}
/* Check if buffer is long enough for insertion */
if (len < (2+p.pl)) {
IRDA_WARNING("%s: buffer too short for insertion!\n",
- __FUNCTION__);
+ __func__);
return -1;
}
- IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
p.pi, p.pl, p.pv.i);
switch (p.pl) {
case 1:
break;
default:
IRDA_WARNING("%s: length %d not supported\n",
- __FUNCTION__, p.pl);
+ __func__, p.pl);
/* Skip parameter */
return -1;
}
if (len < (2+p.pl)) {
IRDA_WARNING("%s: buffer too short for parsing! "
"Need %d bytes, but len is only %d\n",
- __FUNCTION__, p.pl, len);
+ __func__, p.pl, len);
return -1;
}
if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
IRDA_ERROR("%s: invalid parameter length! "
"Expected %d bytes, but value had %d bytes!\n",
- __FUNCTION__, type & PV_MASK, p.pl);
+ __func__, type & PV_MASK, p.pl);
/* Most parameters are bit/byte fields or little endian,
* so it's ok to only extract a subset of it (the subset
break;
default:
IRDA_WARNING("%s: length %d not supported\n",
- __FUNCTION__, p.pl);
+ __func__, p.pl);
/* Skip parameter */
return p.pl+2;
}
- IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
p.pi, p.pl, p.pv.i);
/* Call handler for this parameter */
err = (*func)(self, &p, PV_PUT);
irda_param_t p;
int err;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
p.pi = pi; /* In case handler needs to know */
p.pl = buf[1]; /* Extract length of value */
- IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __func__,
p.pi, p.pl);
/* Check if buffer is long enough for parsing */
if (len < (2+p.pl)) {
IRDA_WARNING("%s: buffer too short for parsing! "
"Need %d bytes, but len is only %d\n",
- __FUNCTION__, p.pl, len);
+ __func__, p.pl, len);
return -1;
}
* checked that the buffer is long enough */
strncpy(str, buf+2, p.pl);
- IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __FUNCTION__,
+ IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __func__,
(__u8) str[0], (__u8) str[1]);
/* Null terminate string */
if (len < (2+p.pl)) {
IRDA_WARNING("%s: buffer too short for parsing! "
"Need %d bytes, but len is only %d\n",
- __FUNCTION__, p.pl, len);
+ __func__, p.pl, len);
return -1;
}
- IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__);
+ IRDA_DEBUG(0, "%s(), not impl\n", __func__);
return p.pl+2; /* Extracted pl+2 bytes */
}
(pi_minor > info->tables[pi_major].len-1))
{
IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
- __FUNCTION__, pi);
+ __func__, pi);
/* Skip this parameter */
return -1;
/* Check if handler has been implemented */
if (!pi_minor_info->func) {
- IRDA_MESSAGE("%s: no handler for pi=%#x\n", __FUNCTION__, pi);
+ IRDA_MESSAGE("%s: no handler for pi=%#x\n", __func__, pi);
/* Skip this parameter */
return -1;
}
(pi_minor > info->tables[pi_major].len-1))
{
IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
- __FUNCTION__, buf[0]);
+ __func__, buf[0]);
/* Skip this parameter */
return 2 + buf[n + 1]; /* Continue */
/* Find expected data type for this parameter identifier (pi)*/
type = pi_minor_info->type;
- IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __FUNCTION__,
+ IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __func__,
pi_major, pi_minor, type);
/* Check if handler has been implemented */
if (!pi_minor_info->func) {
IRDA_MESSAGE("%s: no handler for pi=%#x\n",
- __FUNCTION__, buf[n]);
+ __func__, buf[n]);
/* Skip this parameter */
return 2 + buf[n + 1]; /* Continue */
}
* it's very likely the peer. - Jean II */
if (word == 0) {
IRDA_WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
- __FUNCTION__);
+ __func__);
/* The only safe choice (we don't know the array size) */
word = 0x1;
}
__u32 line_capacity;
int index;
- IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+ IRDA_DEBUG(2, "%s()\n", __func__);
/*
* Make sure the mintt is sensible.
int i;
IRDA_WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
- __FUNCTION__, sysctl_min_tx_turn_time);
+ __func__, sysctl_min_tx_turn_time);
/* We don't really need bits, but easier this way */
i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
{
IRDA_DEBUG(0,
"%s(), adjusting max turn time from %d to 500 ms\n",
- __FUNCTION__, qos->max_turn_time.value);
+ __func__, qos->max_turn_time.value);
qos->max_turn_time.value = 500;
}
while ((qos->data_size.value > line_capacity) && (index > 0)) {
qos->data_size.value = data_sizes[index--];
IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
- __FUNCTION__, qos->data_size.value);
+ __func__, qos->data_size.value);
}
#else /* Use method described in section 6.6.11 of IrLAP */
while (irlap_requested_line_capacity(qos) > line_capacity) {
if (qos->window_size.value > 1) {
qos->window_size.value--;
IRDA_DEBUG(2, "%s(), reducing window size to %d\n",
- __FUNCTION__, qos->window_size.value);
+ __func__, qos->window_size.value);
} else if (index > 1) {
qos->data_size.value = data_sizes[index--];
IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
- __FUNCTION__, qos->data_size.value);
+ __func__, qos->data_size.value);
} else {
IRDA_WARNING("%s(), nothing more we can do!\n",
- __FUNCTION__);
+ __func__);
}
}
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
if (get) {
param->pv.i = self->qos_rx.baud_rate.bits;
IRDA_DEBUG(2, "%s(), baud rate = 0x%02x\n",
- __FUNCTION__, param->pv.i);
+ __func__, param->pv.i);
} else {
/*
* Stations must agree on baud rate, so calculate
int i,j;
IRDA_DEBUG(2, "%s(), speed=%d, max_turn_time=%d\n",
- __FUNCTION__, speed, max_turn_time);
+ __func__, speed, max_turn_time);
i = value_index(speed, baud_rates, 10);
j = value_index(max_turn_time, max_turn_times, 4);
line_capacity = max_line_capacities[i][j];
IRDA_DEBUG(2, "%s(), line capacity=%d bytes\n",
- __FUNCTION__, line_capacity);
+ __func__, line_capacity);
return line_capacity;
}
qos->min_turn_time.value);
IRDA_DEBUG(2, "%s(), requested line capacity=%d\n",
- __FUNCTION__, line_capacity);
+ __func__, line_capacity);
return line_capacity;
}
* Nothing to worry about, but we set the default number of
* BOF's
*/
- IRDA_DEBUG(1, "%s(), wrong magic in skb!\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), wrong magic in skb!\n", __func__);
xbofs = 10;
} else
xbofs = cb->xbofs + cb->xbofs_delay;
- IRDA_DEBUG(4, "%s(), xbofs=%d\n", __FUNCTION__, xbofs);
+ IRDA_DEBUG(4, "%s(), xbofs=%d\n", __func__, xbofs);
/* Check that we never use more than 115 + 48 xbofs */
if (xbofs > 163) {
- IRDA_DEBUG(0, "%s(), too many xbofs (%d)\n", __FUNCTION__,
+ IRDA_DEBUG(0, "%s(), too many xbofs (%d)\n", __func__,
xbofs);
xbofs = 163;
}
*/
if(n >= (buffsize-5)) {
IRDA_ERROR("%s(), tx buffer overflow (n=%d)\n",
- __FUNCTION__, n);
+ __func__, n);
return n;
}
/* Not supposed to happen, the previous frame is not
* finished - Jean II */
IRDA_DEBUG(1, "%s(), Discarding incomplete frame\n",
- __FUNCTION__);
+ __func__);
stats->rx_errors++;
stats->rx_missed_errors++;
irda_device_set_media_busy(dev, TRUE);
/* Wrong CRC, discard frame! */
irda_device_set_media_busy(dev, TRUE);
- IRDA_DEBUG(1, "%s(), crc error\n", __FUNCTION__);
+ IRDA_DEBUG(1, "%s(), crc error\n", __func__);
stats->rx_errors++;
stats->rx_crc_errors++;
}
break;
case LINK_ESCAPE:
- IRDA_WARNING("%s: state not defined\n", __FUNCTION__);
+ IRDA_WARNING("%s: state not defined\n", __func__);
break;
case BEGIN_FRAME:
#endif
} else {
IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n",
- __FUNCTION__);
+ __func__);
rx_buff->state = OUTSIDE_FRAME;
}
break;
rx_buff->state = INSIDE_FRAME;
} else {
IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n",
- __FUNCTION__);
+ __func__);
rx_buff->state = OUTSIDE_FRAME;
}
break;
struct sock sk;
int registered;
int promisc;
+
+ struct {
+ uint8_t msg_version;
+ uint32_t msg_pid;
+ int (*dump)(struct pfkey_sock *sk);
+ void (*done)(struct pfkey_sock *sk);
+ union {
+ struct xfrm_policy_walk policy;
+ struct xfrm_state_walk state;
+ } u;
+ } dump;
};
static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
return (struct pfkey_sock *)sk;
}
+static int pfkey_can_dump(struct sock *sk)
+{
+ if (3 * atomic_read(&sk->sk_rmem_alloc) <= 2 * sk->sk_rcvbuf)
+ return 1;
+ return 0;
+}
+
+static int pfkey_do_dump(struct pfkey_sock *pfk)
+{
+ int rc;
+
+ rc = pfk->dump.dump(pfk);
+ if (rc == -ENOBUFS)
+ return 0;
+
+ pfk->dump.done(pfk);
+ pfk->dump.dump = NULL;
+ pfk->dump.done = NULL;
+ return rc;
+}
+
static void pfkey_sock_destruct(struct sock *sk)
{
skb_queue_purge(&sk->sk_receive_queue);
return 0;
}
-struct pfkey_dump_data
-{
- struct sk_buff *skb;
- struct sadb_msg *hdr;
- struct sock *sk;
-};
-
static int dump_sa(struct xfrm_state *x, int count, void *ptr)
{
- struct pfkey_dump_data *data = ptr;
+ struct pfkey_sock *pfk = ptr;
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
+ if (!pfkey_can_dump(&pfk->sk))
+ return -ENOBUFS;
+
out_skb = pfkey_xfrm_state2msg(x);
if (IS_ERR(out_skb))
return PTR_ERR(out_skb);
out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = data->hdr->sadb_msg_version;
+ out_hdr->sadb_msg_version = pfk->dump.msg_version;
out_hdr->sadb_msg_type = SADB_DUMP;
out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_reserved = 0;
out_hdr->sadb_msg_seq = count;
- out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk);
+ out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);
return 0;
}
+static int pfkey_dump_sa(struct pfkey_sock *pfk)
+{
+ return xfrm_state_walk(&pfk->dump.u.state, dump_sa, (void *) pfk);
+}
+
+static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
+{
+ xfrm_state_walk_done(&pfk->dump.u.state);
+}
+
static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
u8 proto;
- struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+ struct pfkey_sock *pfk = pfkey_sk(sk);
+
+ if (pfk->dump.dump != NULL)
+ return -EBUSY;
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0)
return -EINVAL;
- return xfrm_state_walk(proto, dump_sa, &data);
+ pfk->dump.msg_version = hdr->sadb_msg_version;
+ pfk->dump.msg_pid = hdr->sadb_msg_pid;
+ pfk->dump.dump = pfkey_dump_sa;
+ pfk->dump.done = pfkey_dump_sa_done;
+ xfrm_state_walk_init(&pfk->dump.u.state, proto);
+
+ return pfkey_do_dump(pfk);
}
static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
static u32 gen_reqid(void)
{
+ struct xfrm_policy_walk walk;
u32 start;
+ int rc;
static u32 reqid = IPSEC_MANUAL_REQID_MAX;
start = reqid;
++reqid;
if (reqid == 0)
reqid = IPSEC_MANUAL_REQID_MAX+1;
- if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid,
- (void*)&reqid) != -EEXIST)
+ xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
+ rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid);
+ xfrm_policy_walk_done(&walk);
+ if (rc != -EEXIST)
return reqid;
} while (reqid != start);
return 0;
static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
{
- struct pfkey_dump_data *data = ptr;
+ struct pfkey_sock *pfk = ptr;
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
int err;
+ if (!pfkey_can_dump(&pfk->sk))
+ return -ENOBUFS;
+
out_skb = pfkey_xfrm_policy2msg_prep(xp);
if (IS_ERR(out_skb))
return PTR_ERR(out_skb);
return err;
out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = data->hdr->sadb_msg_version;
+ out_hdr->sadb_msg_version = pfk->dump.msg_version;
out_hdr->sadb_msg_type = SADB_X_SPDDUMP;
out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = count;
- out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk);
+ out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);
return 0;
}
+static int pfkey_dump_sp(struct pfkey_sock *pfk)
+{
+ return xfrm_policy_walk(&pfk->dump.u.policy, dump_sp, (void *) pfk);
+}
+
+static void pfkey_dump_sp_done(struct pfkey_sock *pfk)
+{
+ xfrm_policy_walk_done(&pfk->dump.u.policy);
+}
+
static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
- struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+ struct pfkey_sock *pfk = pfkey_sk(sk);
+
+ if (pfk->dump.dump != NULL)
+ return -EBUSY;
+
+ pfk->dump.msg_version = hdr->sadb_msg_version;
+ pfk->dump.msg_pid = hdr->sadb_msg_pid;
+ pfk->dump.dump = pfkey_dump_sp;
+ pfk->dump.done = pfkey_dump_sp_done;
+ xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN);
- return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data);
+ return pfkey_do_dump(pfk);
}
static int key_notify_policy_flush(struct km_event *c)
int flags)
{
struct sock *sk = sock->sk;
+ struct pfkey_sock *pfk = pfkey_sk(sk);
struct sk_buff *skb;
int copied, err;
err = (flags & MSG_TRUNC) ? skb->len : copied;
+ if (pfk->dump.dump != NULL &&
+ 3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
+ pfkey_do_dump(pfk);
+
out_free:
skb_free_datagram(sk, skb);
out:
sock_hold(sk);
lock_sock(sk);
llc = llc_sk(sk);
- dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__,
+ dprintk("%s: closing local(%02X) remote(%02X)\n", __func__,
llc->laddr.lsap, llc->daddr.lsap);
if (!llc_send_disc(sk))
llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
struct llc_sap *sap;
int rc = -EINVAL;
- dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_sap);
+ dprintk("%s: binding %02X\n", __func__, addr->sllc_sap);
if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr)))
goto out;
rc = -EAFNOSUPPORT;
rc = llc_establish_connection(sk, llc->dev->dev_addr,
addr->sllc_mac, addr->sllc_sap);
if (rc) {
- dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
+ dprintk("%s: llc_ui_send_conn failed :-(\n", __func__);
sock->state = SS_UNCONNECTED;
sk->sk_state = TCP_CLOSE;
goto out;
struct sk_buff *skb;
int rc = -EOPNOTSUPP;
- dprintk("%s: accepting on %02X\n", __FUNCTION__,
+ dprintk("%s: accepting on %02X\n", __func__,
llc_sk(sk)->laddr.lsap);
lock_sock(sk);
if (unlikely(sk->sk_type != SOCK_STREAM))
if (rc)
goto out;
}
- dprintk("%s: got a new connection on %02X\n", __FUNCTION__,
+ dprintk("%s: got a new connection on %02X\n", __func__,
llc_sk(sk)->laddr.lsap);
skb = skb_dequeue(&sk->sk_receive_queue);
rc = -EINVAL;
/* put original socket back into a clean listen state. */
sk->sk_state = TCP_LISTEN;
sk->sk_ack_backlog--;
- dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,
+ dprintk("%s: ok success on %02X, client on %02X\n", __func__,
llc_sk(sk)->addr.sllc_sap, newllc->daddr.lsap);
frees:
kfree_skb(skb);
size_t size = 0;
int rc = -EINVAL, copied = 0, hdrlen;
- dprintk("%s: sending from %02X to %02X\n", __FUNCTION__,
+ dprintk("%s: sending from %02X to %02X\n", __func__,
llc->laddr.lsap, llc->daddr.lsap);
lock_sock(sk);
if (addr) {
kfree_skb(skb);
release:
dprintk("%s: failed sending from %02X to %02X: %d\n",
- __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc);
+ __func__, llc->laddr.lsap, llc->daddr.lsap, rc);
}
release_sock(sk);
return rc ? : copied;
{
if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
printk(KERN_WARNING "%s: timer called on closed connection\n",
- __FUNCTION__);
+ __func__);
kfree_skb(skb);
} else {
if (!sock_owned_by_user(sk))
llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
if (!rc)
dprintk("%s: matched, state=%d, ns=%d, vr=%d\n",
- __FUNCTION__, llc_sk(sk)->state, ns, vr);
+ __func__, llc_sk(sk)->state, ns, vr);
return rc;
}
llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
if (!rc)
dprintk("%s: matched, state=%d, ns=%d, vr=%d\n",
- __FUNCTION__, llc_sk(sk)->state, ns, vr);
+ __func__, llc_sk(sk)->state, ns, vr);
return rc;
}
(LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) &&
nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
dprintk("%s: matched, state=%d, vs=%d, nr=%d\n",
- __FUNCTION__, llc_sk(sk)->state, vs, nr);
+ __func__, llc_sk(sk)->state, vs, nr);
rc = 0;
}
return rc;
nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
rc = 0;
dprintk("%s: matched, state=%d, vs=%d, nr=%d\n",
- __FUNCTION__, llc_sk(sk)->state, vs, nr);
+ __func__, llc_sk(sk)->state, vs, nr);
}
return rc;
}
*/
rc = llc_conn_service(skb->sk, skb);
if (unlikely(rc != 0)) {
- printk(KERN_ERR "%s: llc_conn_service failed\n", __FUNCTION__);
+ printk(KERN_ERR "%s: llc_conn_service failed\n", __func__);
goto out_kfree_skb;
}
* shouldn't happen
*/
printk(KERN_ERR "%s: sock_queue_rcv_skb failed!\n",
- __FUNCTION__);
+ __func__);
kfree_skb(skb);
}
break;
* FIXME:
* RESET is not being notified to upper layers for now
*/
- printk(KERN_INFO "%s: received a reset ind!\n", __FUNCTION__);
+ printk(KERN_INFO "%s: received a reset ind!\n", __func__);
kfree_skb(skb);
break;
default:
if (ev->ind_prim) {
printk(KERN_INFO "%s: received unknown %d prim!\n",
- __FUNCTION__, ev->ind_prim);
+ __func__, ev->ind_prim);
kfree_skb(skb);
}
/* No indication */
* FIXME:
* RESET is not being notified to upper layers for now
*/
- printk(KERN_INFO "%s: received a reset conf!\n", __FUNCTION__);
+ printk(KERN_INFO "%s: received a reset conf!\n", __func__);
break;
default:
if (ev->cfm_prim) {
printk(KERN_INFO "%s: received unknown %d prim!\n",
- __FUNCTION__, ev->cfm_prim);
+ __func__, ev->cfm_prim);
break;
}
goto out_skb_put; /* No confirmation */
if (!sock_owned_by_user(sk))
llc_conn_rcv(sk, skb);
else {
- dprintk("%s: adding to backlog...\n", __FUNCTION__);
+ dprintk("%s: adding to backlog...\n", __func__);
llc_set_backlog_type(skb, LLC_PACKET);
sk_add_backlog(sk, skb);
}
else
goto out_kfree_skb;
} else {
- printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__);
+ printk(KERN_ERR "%s: invalid skb in backlog\n", __func__);
goto out_kfree_skb;
}
out:
#ifdef LLC_REFCNT_DEBUG
atomic_inc(&llc_sock_nr);
printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,
- __FUNCTION__, atomic_read(&llc_sock_nr));
+ __func__, atomic_read(&llc_sock_nr));
#endif
out:
return sk;
/* Stop all (possibly) running timers */
llc_conn_ac_stop_all_timers(sk, NULL);
#ifdef DEBUG_LLC_CONN_ALLOC
- printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,
+ printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __func__,
skb_queue_len(&llc->pdu_unack_q),
skb_queue_len(&sk->sk_write_queue));
#endif
#ifdef LLC_REFCNT_DEBUG
if (atomic_read(&sk->sk_refcnt) != 1) {
printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n",
- sk, __FUNCTION__, atomic_read(&sk->sk_refcnt));
+ sk, __func__, atomic_read(&sk->sk_refcnt));
printk(KERN_DEBUG "%d LLC sockets are still alive\n",
atomic_read(&llc_sock_nr));
} else {
atomic_dec(&llc_sock_nr);
printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk,
- __FUNCTION__, atomic_read(&llc_sock_nr));
+ __func__, atomic_read(&llc_sock_nr));
}
#endif
sock_put(sk);
* receives, do not try to analyse it.
*/
if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) {
- dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__);
+ dprintk("%s: PACKET_OTHERHOST\n", __func__);
goto drop;
}
skb = skb_share_check(skb, GFP_ATOMIC);
goto handle_station;
sap = llc_sap_find(pdu->dsap);
if (unlikely(!sap)) {/* unknown SAP */
- dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__,
+ dprintk("%s: llc_sap_find(%02X) failed!\n", __func__,
pdu->dsap);
goto drop;
}
default rate control algorithm. You should choose
this unless you know what you are doing.
-config MAC80211_RC_DEFAULT_SIMPLE
- bool "Simple rate control algorithm"
- select MAC80211_RC_SIMPLE
- ---help---
- Select the simple rate control as the default rate
- control algorithm. Note that this is a non-responsive,
- dumb algorithm. You should choose the PID rate control
- instead.
-
config MAC80211_RC_DEFAULT_NONE
bool "No default algorithm"
depends on EMBEDDED
config MAC80211_RC_DEFAULT
string
default "pid" if MAC80211_RC_DEFAULT_PID
- default "simple" if MAC80211_RC_DEFAULT_SIMPLE
default ""
config MAC80211_RC_PID
Say Y or M unless you're sure you want to use a
different rate control algorithm.
-config MAC80211_RC_SIMPLE
- tristate "Simple rate control algorithm (DEPRECATED)"
+endmenu
+
+config MAC80211_MESH
+ bool "Enable mac80211 mesh networking (pre-802.11s) support"
+ depends on MAC80211 && EXPERIMENTAL
---help---
- This option enables a very simple, non-responsive TX
- rate control algorithm. This algorithm is deprecated
- and will be removed from the kernel in the near future.
- It has been replaced by the PID algorithm.
+ This options enables support of Draft 802.11s mesh networking.
+ The implementation is based on Draft 1.08 of the Mesh Networking
+ amendment. For more information visit http://o11s.org/.
- Say N unless you know what you are doing.
-endmenu
config MAC80211_LEDS
bool "Enable LED triggers"
---help---
Say Y here to print out verbose powersave
mode debug messages.
+
+config MAC80211_VERBOSE_MPL_DEBUG
+ bool "Verbose mesh peer link debugging"
+ depends on MAC80211_DEBUG && MAC80211_MESH
+ ---help---
+ Say Y here to print out verbose mesh peer link
+ debug messages.
ieee80211_iface.o \
ieee80211_rate.o \
michael.o \
- regdomain.o \
tkip.o \
aes_ccm.o \
cfg.o \
debugfs_netdev.o \
debugfs_key.o
+mac80211-$(CONFIG_MAC80211_MESH) += \
+ mesh.o \
+ mesh_pathtbl.o \
+ mesh_plink.o \
+ mesh_hwmp.o
+
# Build rate control algorithm(s)
-CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE
CFLAGS_rc80211_pid_algo.o += -DRC80211_PID_COMPILE
-mac80211-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o
mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc-pid-$(CONFIG_MAC80211_RC_PID))
# Modular rate algorithms are assigned to mac80211-m - make separate modules
#include "ieee80211_i.h"
#include "cfg.h"
#include "ieee80211_rate.h"
+#include "mesh.h"
static enum ieee80211_if_types
nl80211_type_to_mac80211_type(enum nl80211_iftype type)
return IEEE80211_IF_TYPE_STA;
case NL80211_IFTYPE_MONITOR:
return IEEE80211_IF_TYPE_MNTR;
+#ifdef CONFIG_MAC80211_MESH
+ case NL80211_IFTYPE_MESH_POINT:
+ return IEEE80211_IF_TYPE_MESH_POINT;
+#endif
default:
return IEEE80211_IF_TYPE_INVALID;
}
}
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
- enum nl80211_iftype type)
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
enum ieee80211_if_types itype;
+ struct net_device *dev;
+ struct ieee80211_sub_if_data *sdata;
+ int err;
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
return -ENODEV;
if (itype == IEEE80211_IF_TYPE_INVALID)
return -EINVAL;
- return ieee80211_if_add(local->mdev, name, NULL, itype);
+ err = ieee80211_if_add(local->mdev, name, &dev, itype, params);
+ if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
+ return err;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ sdata->u.mntr_flags = *flags;
+ return 0;
}
static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
}
static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
- enum nl80211_iftype type)
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct net_device *dev;
ieee80211_if_reinit(dev);
ieee80211_if_set_type(dev, itype);
+ if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
+ ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+ params->mesh_id_len,
+ params->mesh_id);
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
+ return 0;
+
+ sdata->u.mntr_flags = *flags;
return 0;
}
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta = NULL;
enum ieee80211_key_alg alg;
- int ret;
+ struct ieee80211_key *key;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
return -EINVAL;
}
+ key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key);
+ if (!key)
+ return -ENOMEM;
+
if (mac_addr) {
sta = sta_info_get(sdata->local, mac_addr);
- if (!sta)
+ if (!sta) {
+ ieee80211_key_free(key);
return -ENOENT;
+ }
}
- ret = 0;
- if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
- params->key_len, params->key))
- ret = -ENOMEM;
-
- if (sta)
- sta_info_put(sta);
+ ieee80211_key_link(key, sdata, sta);
- return ret;
+ return 0;
}
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
return -ENOENT;
ret = 0;
- if (sta->key)
+ if (sta->key) {
ieee80211_key_free(sta->key);
- else
+ WARN_ON(sta->key);
+ } else
ret = -ENOENT;
- sta_info_put(sta);
return ret;
}
return -ENOENT;
ieee80211_key_free(sdata->keys[key_idx]);
+ WARN_ON(sdata->keys[key_idx]);
return 0;
}
err = 0;
out:
- if (sta)
- sta_info_put(sta);
return err;
}
return 0;
}
+static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+ sinfo->filled = STATION_INFO_INACTIVE_TIME |
+ STATION_INFO_RX_BYTES |
+ STATION_INFO_TX_BYTES;
+
+ sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+ sinfo->rx_bytes = sta->rx_bytes;
+ sinfo->tx_bytes = sta->tx_bytes;
+
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+#ifdef CONFIG_MAC80211_MESH
+ sinfo->filled |= STATION_INFO_LLID |
+ STATION_INFO_PLID |
+ STATION_INFO_PLINK_STATE;
+
+ sinfo->llid = le16_to_cpu(sta->llid);
+ sinfo->plid = le16_to_cpu(sta->plid);
+ sinfo->plink_state = sta->plink_state;
+#endif
+ }
+}
+
+
+static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *mac, struct station_info *sinfo)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ int ret = -ENOENT;
+
+ rcu_read_lock();
+
+ sta = sta_info_get_by_idx(local, idx, dev);
+ if (sta) {
+ ret = 0;
+ memcpy(mac, sta->addr, ETH_ALEN);
+ sta_set_sinfo(sta, sinfo);
+ }
+
+ rcu_read_unlock();
+
+ return ret;
+}
+
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
- u8 *mac, struct station_stats *stats)
+ u8 *mac, struct station_info *sinfo)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
+ int ret = -ENOENT;
- sta = sta_info_get(local, mac);
- if (!sta)
- return -ENOENT;
+ rcu_read_lock();
/* XXX: verify sta->dev == dev */
- stats->filled = STATION_STAT_INACTIVE_TIME |
- STATION_STAT_RX_BYTES |
- STATION_STAT_TX_BYTES;
-
- stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
- stats->rx_bytes = sta->rx_bytes;
- stats->tx_bytes = sta->tx_bytes;
+ sta = sta_info_get(local, mac);
+ if (sta) {
+ ret = 0;
+ sta_set_sinfo(sta, sinfo);
+ }
- sta_info_put(sta);
+ rcu_read_unlock();
- return 0;
+ return ret;
}
/*
msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
- skb->dev = sta->dev;
- skb->protocol = eth_type_trans(skb, sta->dev);
+ skb->dev = sta->sdata->dev;
+ skb->protocol = eth_type_trans(skb, sta->sdata->dev);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx(skb);
}
{
u32 rates;
int i, j;
- struct ieee80211_hw_mode *mode;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+ /*
+ * FIXME: updating the flags is racy when this function is
+ * called from ieee80211_change_station(), this will
+ * be resolved in a future patch.
+ */
if (params->station_flags & STATION_FLAG_CHANGED) {
sta->flags &= ~WLAN_STA_AUTHORIZED;
sta->flags |= WLAN_STA_WME;
}
+ /*
+ * FIXME: updating the following information is racy when this
+ * function is called from ieee80211_change_station().
+ * However, all this information should be static so
+ * maybe we should just reject attemps to change it.
+ */
+
if (params->aid) {
sta->aid = params->aid;
if (sta->aid > IEEE80211_MAX_AID)
if (params->supported_rates) {
rates = 0;
- mode = local->oper_hw_mode;
+ sband = local->hw.wiphy->bands[local->oper_channel->band];
+
for (i = 0; i < params->supported_rates_len; i++) {
int rate = (params->supported_rates[i] & 0x7f) * 5;
- for (j = 0; j < mode->num_rates; j++) {
- if (mode->rates[j].rate == rate)
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].bitrate == rate)
rates |= BIT(j);
}
}
- sta->supp_rates = rates;
+ sta->supp_rates[local->oper_channel->band] = rates;
+ }
+
+ if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
+ switch (params->plink_action) {
+ case PLINK_ACTION_OPEN:
+ mesh_plink_open(sta);
+ break;
+ case PLINK_ACTION_BLOCK:
+ mesh_plink_block(sta);
+ break;
+ }
}
}
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata;
+ int err;
/* Prevent a race with changing the rate control algorithm */
if (!netif_running(dev))
return -ENETDOWN;
- /* XXX: get sta belonging to dev */
- sta = sta_info_get(local, mac);
- if (sta) {
- sta_info_put(sta);
- return -EEXIST;
- }
-
if (params->vlan) {
sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
} else
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sta = sta_info_add(local, dev, mac, GFP_KERNEL);
+ if (compare_ether_addr(mac, dev->dev_addr) == 0)
+ return -EINVAL;
+
+ if (is_multicast_ether_addr(mac))
+ return -EINVAL;
+
+ sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
if (!sta)
return -ENOMEM;
- sta->dev = sdata->dev;
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
- sdata->vif.type == IEEE80211_IF_TYPE_AP)
- ieee80211_send_layer2_update(sta);
-
sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
sta_apply_parameters(local, sta, params);
rate_control_rate_init(sta, local);
- sta_info_put(sta);
+ rcu_read_lock();
+
+ err = sta_info_insert(sta);
+ if (err) {
+ sta_info_destroy(sta);
+ rcu_read_unlock();
+ return err;
+ }
+
+ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
+ sdata->vif.type == IEEE80211_IF_TYPE_AP)
+ ieee80211_send_layer2_update(sta);
+
+ rcu_read_unlock();
return 0;
}
static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
if (mac) {
if (!sta)
return -ENOENT;
- sta_info_free(sta);
- sta_info_put(sta);
+ sta_info_unlink(&sta);
+
+ if (sta) {
+ synchronize_rcu();
+ sta_info_destroy(sta);
+ }
} else
- sta_info_flush(local, dev);
+ sta_info_flush(local, sdata);
return 0;
}
if (!sta)
return -ENOENT;
- if (params->vlan && params->vlan != sta->dev) {
+ if (params->vlan && params->vlan != sta->sdata->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
- sta->dev = params->vlan;
+ sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
ieee80211_send_layer2_update(sta);
}
sta_apply_parameters(local, sta, params);
- sta_info_put(sta);
+ return 0;
+}
+
+#ifdef CONFIG_MAC80211_MESH
+static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+ struct sta_info *sta;
+ int err;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ return -ENOTSUPP;
+
+ rcu_read_lock();
+ sta = sta_info_get(local, next_hop);
+ if (!sta) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ err = mesh_path_add(dst, dev);
+ if (err) {
+ rcu_read_unlock();
+ return err;
+ }
+
+ mpath = mesh_path_lookup(dst, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+ mesh_path_fix_nexthop(mpath, sta);
+
+ rcu_read_unlock();
+ return 0;
+}
+static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst)
+{
+ if (dst)
+ return mesh_path_del(dst, dev);
+
+ mesh_path_flush(dev);
+ return 0;
+}
+
+static int ieee80211_change_mpath(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 *dst, u8 *next_hop)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+ struct sta_info *sta;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ return -ENOTSUPP;
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, next_hop);
+ if (!sta) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ mpath = mesh_path_lookup(dst, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ mesh_path_fix_nexthop(mpath, sta);
+
+ rcu_read_unlock();
+ return 0;
+}
+
+static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
+ struct mpath_info *pinfo)
+{
+ if (mpath->next_hop)
+ memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+ else
+ memset(next_hop, 0, ETH_ALEN);
+
+ pinfo->filled = MPATH_INFO_FRAME_QLEN |
+ MPATH_INFO_DSN |
+ MPATH_INFO_METRIC |
+ MPATH_INFO_EXPTIME |
+ MPATH_INFO_DISCOVERY_TIMEOUT |
+ MPATH_INFO_DISCOVERY_RETRIES |
+ MPATH_INFO_FLAGS;
+
+ pinfo->frame_qlen = mpath->frame_queue.qlen;
+ pinfo->dsn = mpath->dsn;
+ pinfo->metric = mpath->metric;
+ if (time_before(jiffies, mpath->exp_time))
+ pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies);
+ pinfo->discovery_timeout =
+ jiffies_to_msecs(mpath->discovery_timeout);
+ pinfo->discovery_retries = mpath->discovery_retries;
+ pinfo->flags = 0;
+ if (mpath->flags & MESH_PATH_ACTIVE)
+ pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE;
+ if (mpath->flags & MESH_PATH_RESOLVING)
+ pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
+ if (mpath->flags & MESH_PATH_DSN_VALID)
+ pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID;
+ if (mpath->flags & MESH_PATH_FIXED)
+ pinfo->flags |= NL80211_MPATH_FLAG_FIXED;
+ if (mpath->flags & MESH_PATH_RESOLVING)
+ pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
+
+ pinfo->flags = mpath->flags;
+}
+
+static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
+
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ return -ENOTSUPP;
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ memcpy(dst, mpath->dst, ETH_ALEN);
+ mpath_set_pinfo(mpath, next_hop, pinfo);
+ rcu_read_unlock();
+ return 0;
+}
+
+static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ return -ENOTSUPP;
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup_by_idx(idx, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ memcpy(dst, mpath->dst, ETH_ALEN);
+ mpath_set_pinfo(mpath, next_hop, pinfo);
+ rcu_read_unlock();
return 0;
}
+#endif
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_station = ieee80211_del_station,
.change_station = ieee80211_change_station,
.get_station = ieee80211_get_station,
+ .dump_station = ieee80211_dump_station,
+#ifdef CONFIG_MAC80211_MESH
+ .add_mpath = ieee80211_add_mpath,
+ .del_mpath = ieee80211_del_mpath,
+ .change_mpath = ieee80211_change_mpath,
+ .get_mpath = ieee80211_get_mpath,
+ .dump_mpath = ieee80211_dump_mpath,
+#endif
};
return 0;
}
-static const char *ieee80211_mode_str(int mode)
-{
- switch (mode) {
- case MODE_IEEE80211A:
- return "IEEE 802.11a";
- case MODE_IEEE80211B:
- return "IEEE 802.11b";
- case MODE_IEEE80211G:
- return "IEEE 802.11g";
- default:
- return "UNKNOWN";
- }
-}
-
-static ssize_t modes_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- struct ieee80211_hw_mode *mode;
- char buf[150], *p = buf;
-
- /* FIXME: locking! */
- list_for_each_entry(mode, &local->modes_list, list) {
- p += scnprintf(p, sizeof(buf)+buf-p,
- "%s\n", ieee80211_mode_str(mode->mode));
- }
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
-}
-
-static const struct file_operations modes_ops = {
- .read = modes_read,
- .open = mac80211_open_file_generic,
-};
-
#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \
static ssize_t name## _read(struct file *file, char __user *userbuf, \
size_t count, loff_t *ppos) \
local->debugfs.name = NULL;
-DEBUGFS_READONLY_FILE(channel, 20, "%d",
- local->hw.conf.channel);
DEBUGFS_READONLY_FILE(frequency, 20, "%d",
- local->hw.conf.freq);
+ local->hw.conf.channel->center_freq);
DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
local->hw.conf.antenna_sel_tx);
DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
local->long_retry_limit);
DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
local->total_ps_buffered);
-DEBUGFS_READONLY_FILE(mode, 20, "%s",
- ieee80211_mode_str(local->hw.conf.phymode));
DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
local->wep_iv & 0xffffff);
DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
local->debugfs.stations = debugfs_create_dir("stations", phyd);
local->debugfs.keys = debugfs_create_dir("keys", phyd);
- DEBUGFS_ADD(channel);
DEBUGFS_ADD(frequency);
DEBUGFS_ADD(antenna_sel_tx);
DEBUGFS_ADD(antenna_sel_rx);
DEBUGFS_ADD(short_retry_limit);
DEBUGFS_ADD(long_retry_limit);
DEBUGFS_ADD(total_ps_buffered);
- DEBUGFS_ADD(mode);
DEBUGFS_ADD(wep_iv);
- DEBUGFS_ADD(modes);
statsd = debugfs_create_dir("statistics", phyd);
local->debugfs.statistics = statsd;
void debugfs_hw_del(struct ieee80211_local *local)
{
- DEBUGFS_DEL(channel);
DEBUGFS_DEL(frequency);
DEBUGFS_DEL(antenna_sel_tx);
DEBUGFS_DEL(antenna_sel_rx);
DEBUGFS_DEL(short_retry_limit);
DEBUGFS_DEL(long_retry_limit);
DEBUGFS_DEL(total_ps_buffered);
- DEBUGFS_DEL(mode);
DEBUGFS_DEL(wep_iv);
- DEBUGFS_DEL(modes);
DEBUGFS_STATS_DEL(transmitted_fragment_count);
DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);
return ret;
}
+#ifdef CONFIG_MAC80211_MESH
+static ssize_t ieee80211_if_write(
+ struct ieee80211_sub_if_data *sdata,
+ char const __user *userbuf,
+ size_t count, loff_t *ppos,
+ int (*format)(struct ieee80211_sub_if_data *, char *))
+{
+ char buf[10];
+ int buf_size;
+
+ memset(buf, 0x00, sizeof(buf));
+ buf_size = min(count, (sizeof(buf)-1));
+ read_lock(&dev_base_lock);
+ if (copy_from_user(buf, userbuf, buf_size))
+ goto endwrite;
+ if (sdata->dev->reg_state == NETREG_REGISTERED)
+ (*format)(sdata, buf);
+endwrite:
+ read_unlock(&dev_base_lock);
+ return count;
+}
+#endif
+
#define IEEE80211_IF_FMT(name, field, format_string) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, char *buf, \
{ \
return scnprintf(buf, buflen, format_string, sdata->field); \
}
+#define IEEE80211_IF_WFMT(name, field, type) \
+static int ieee80211_if_wfmt_##name( \
+ struct ieee80211_sub_if_data *sdata, char *buf) \
+{ \
+ unsigned long tmp; \
+ char *endp; \
+ \
+ tmp = simple_strtoul(buf, &endp, 0); \
+ if ((endp == buf) || ((type)tmp != tmp)) \
+ return -EINVAL; \
+ sdata->field = tmp; \
+ return 0; \
+}
#define IEEE80211_IF_FMT_DEC(name, field) \
IEEE80211_IF_FMT(name, field, "%d\n")
#define IEEE80211_IF_FMT_HEX(name, field) \
IEEE80211_IF_FMT_##format(name, field) \
__IEEE80211_IF_FILE(name)
+#define __IEEE80211_IF_WFILE(name) \
+static ssize_t ieee80211_if_read_##name(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ return ieee80211_if_read(file->private_data, \
+ userbuf, count, ppos, \
+ ieee80211_if_fmt_##name); \
+} \
+static ssize_t ieee80211_if_write_##name(struct file *file, \
+ const char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ return ieee80211_if_write(file->private_data, \
+ userbuf, count, ppos, \
+ ieee80211_if_wfmt_##name); \
+} \
+static const struct file_operations name##_ops = { \
+ .read = ieee80211_if_read_##name, \
+ .write = ieee80211_if_write_##name, \
+ .open = mac80211_open_file_generic, \
+}
+
+#define IEEE80211_IF_WFILE(name, field, format, type) \
+ IEEE80211_IF_FMT_##format(name, field) \
+ IEEE80211_IF_WFMT(name, field, type) \
+ __IEEE80211_IF_WFILE(name)
+
/* common attributes */
IEEE80211_IF_FILE(channel_use, channel_use, DEC);
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
-IEEE80211_IF_FILE(ieee802_1x_pac, ieee802_1x_pac, DEC);
/* STA/IBSS attributes */
IEEE80211_IF_FILE(state, u.sta.state, DEC);
IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
+IEEE80211_IF_FILE(num_beacons_sta, u.sta.num_beacons, DEC);
static ssize_t ieee80211_if_fmt_flags(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
/* WDS attributes */
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
+#ifdef CONFIG_MAC80211_MESH
+/* Mesh stats attributes */
+IEEE80211_IF_FILE(fwded_frames, u.sta.mshstats.fwded_frames, DEC);
+IEEE80211_IF_FILE(dropped_frames_ttl, u.sta.mshstats.dropped_frames_ttl, DEC);
+IEEE80211_IF_FILE(dropped_frames_no_route,
+ u.sta.mshstats.dropped_frames_no_route, DEC);
+IEEE80211_IF_FILE(estab_plinks, u.sta.mshstats.estab_plinks, ATOMIC);
+
+/* Mesh parameters */
+IEEE80211_IF_WFILE(dot11MeshMaxRetries,
+ u.sta.mshcfg.dot11MeshMaxRetries, DEC, u8);
+IEEE80211_IF_WFILE(dot11MeshRetryTimeout,
+ u.sta.mshcfg.dot11MeshRetryTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshConfirmTimeout,
+ u.sta.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
+ u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8);
+IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, bool);
+IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
+ u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
+ u.sta.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
+IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval,
+ u.sta.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime,
+ u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries,
+ u.sta.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
+IEEE80211_IF_WFILE(path_refresh_time,
+ u.sta.mshcfg.path_refresh_time, DEC, u32);
+IEEE80211_IF_WFILE(min_discovery_timeout,
+ u.sta.mshcfg.min_discovery_timeout, DEC, u16);
+#endif
+
+
#define DEBUGFS_ADD(name, type)\
sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
sdata->debugfsdir, sdata, &name##_ops);
{
DEBUGFS_ADD(channel_use, sta);
DEBUGFS_ADD(drop_unencrypted, sta);
- DEBUGFS_ADD(ieee802_1x_pac, sta);
DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta);
DEBUGFS_ADD(prev_bssid, sta);
DEBUGFS_ADD(auth_alg, sta);
DEBUGFS_ADD(auth_transaction, sta);
DEBUGFS_ADD(flags, sta);
+ DEBUGFS_ADD(num_beacons_sta, sta);
}
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(channel_use, ap);
DEBUGFS_ADD(drop_unencrypted, ap);
- DEBUGFS_ADD(ieee802_1x_pac, ap);
DEBUGFS_ADD(num_sta_ps, ap);
DEBUGFS_ADD(dtim_count, ap);
DEBUGFS_ADD(num_beacons, ap);
{
DEBUGFS_ADD(channel_use, wds);
DEBUGFS_ADD(drop_unencrypted, wds);
- DEBUGFS_ADD(ieee802_1x_pac, wds);
DEBUGFS_ADD(peer, wds);
}
{
DEBUGFS_ADD(channel_use, vlan);
DEBUGFS_ADD(drop_unencrypted, vlan);
- DEBUGFS_ADD(ieee802_1x_pac, vlan);
}
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
{
}
+#ifdef CONFIG_MAC80211_MESH
+#define MESHSTATS_ADD(name)\
+ sdata->mesh_stats.name = debugfs_create_file(#name, 0444,\
+ sdata->mesh_stats_dir, sdata, &name##_ops);
+
+static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
+{
+ sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats",
+ sdata->debugfsdir);
+ MESHSTATS_ADD(fwded_frames);
+ MESHSTATS_ADD(dropped_frames_ttl);
+ MESHSTATS_ADD(dropped_frames_no_route);
+ MESHSTATS_ADD(estab_plinks);
+}
+
+#define MESHPARAMS_ADD(name)\
+ sdata->mesh_config.name = debugfs_create_file(#name, 0644,\
+ sdata->mesh_config_dir, sdata, &name##_ops);
+
+static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
+{
+ sdata->mesh_config_dir = debugfs_create_dir("mesh_config",
+ sdata->debugfsdir);
+ MESHPARAMS_ADD(dot11MeshMaxRetries);
+ MESHPARAMS_ADD(dot11MeshRetryTimeout);
+ MESHPARAMS_ADD(dot11MeshConfirmTimeout);
+ MESHPARAMS_ADD(dot11MeshHoldingTimeout);
+ MESHPARAMS_ADD(dot11MeshTTL);
+ MESHPARAMS_ADD(auto_open_plinks);
+ MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
+ MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
+ MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
+ MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
+ MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
+ MESHPARAMS_ADD(path_refresh_time);
+ MESHPARAMS_ADD(min_discovery_timeout);
+}
+#endif
+
static void add_files(struct ieee80211_sub_if_data *sdata)
{
if (!sdata->debugfsdir)
return;
switch (sdata->vif.type) {
+ case IEEE80211_IF_TYPE_MESH_POINT:
+#ifdef CONFIG_MAC80211_MESH
+ add_mesh_stats(sdata);
+ add_mesh_config(sdata);
+#endif
+ /* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
add_sta_files(sdata);
{
DEBUGFS_DEL(channel_use, sta);
DEBUGFS_DEL(drop_unencrypted, sta);
- DEBUGFS_DEL(ieee802_1x_pac, sta);
DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta);
DEBUGFS_DEL(prev_bssid, sta);
DEBUGFS_DEL(auth_alg, sta);
DEBUGFS_DEL(auth_transaction, sta);
DEBUGFS_DEL(flags, sta);
+ DEBUGFS_DEL(num_beacons_sta, sta);
}
static void del_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(channel_use, ap);
DEBUGFS_DEL(drop_unencrypted, ap);
- DEBUGFS_DEL(ieee802_1x_pac, ap);
DEBUGFS_DEL(num_sta_ps, ap);
DEBUGFS_DEL(dtim_count, ap);
DEBUGFS_DEL(num_beacons, ap);
{
DEBUGFS_DEL(channel_use, wds);
DEBUGFS_DEL(drop_unencrypted, wds);
- DEBUGFS_DEL(ieee802_1x_pac, wds);
DEBUGFS_DEL(peer, wds);
}
{
DEBUGFS_DEL(channel_use, vlan);
DEBUGFS_DEL(drop_unencrypted, vlan);
- DEBUGFS_DEL(ieee802_1x_pac, vlan);
}
static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
{
}
+#ifdef CONFIG_MAC80211_MESH
+#define MESHSTATS_DEL(name) \
+ do { \
+ debugfs_remove(sdata->mesh_stats.name); \
+ sdata->mesh_stats.name = NULL; \
+ } while (0)
+
+static void del_mesh_stats(struct ieee80211_sub_if_data *sdata)
+{
+ MESHSTATS_DEL(fwded_frames);
+ MESHSTATS_DEL(dropped_frames_ttl);
+ MESHSTATS_DEL(dropped_frames_no_route);
+ MESHSTATS_DEL(estab_plinks);
+ debugfs_remove(sdata->mesh_stats_dir);
+ sdata->mesh_stats_dir = NULL;
+}
+
+#define MESHPARAMS_DEL(name) \
+ do { \
+ debugfs_remove(sdata->mesh_config.name); \
+ sdata->mesh_config.name = NULL; \
+ } while (0)
+
+static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
+{
+ MESHPARAMS_DEL(dot11MeshMaxRetries);
+ MESHPARAMS_DEL(dot11MeshRetryTimeout);
+ MESHPARAMS_DEL(dot11MeshConfirmTimeout);
+ MESHPARAMS_DEL(dot11MeshHoldingTimeout);
+ MESHPARAMS_DEL(dot11MeshTTL);
+ MESHPARAMS_DEL(auto_open_plinks);
+ MESHPARAMS_DEL(dot11MeshMaxPeerLinks);
+ MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout);
+ MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval);
+ MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime);
+ MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries);
+ MESHPARAMS_DEL(path_refresh_time);
+ MESHPARAMS_DEL(min_discovery_timeout);
+ debugfs_remove(sdata->mesh_config_dir);
+ sdata->mesh_config_dir = NULL;
+}
+#endif
+
static void del_files(struct ieee80211_sub_if_data *sdata, int type)
{
if (!sdata->debugfsdir)
return;
switch (type) {
+ case IEEE80211_IF_TYPE_MESH_POINT:
+#ifdef CONFIG_MAC80211_MESH
+ del_mesh_stats(sdata);
+ del_mesh_config(sdata);
+#endif
+ /* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
del_sta_files(sdata);
#define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
#define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
-#define STA_READ_RATE(name, field) \
-static ssize_t sta_##name##_read(struct file *file, \
- char __user *userbuf, \
- size_t count, loff_t *ppos) \
-{ \
- struct sta_info *sta = file->private_data; \
- struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\
- struct ieee80211_hw_mode *mode = local->oper_hw_mode; \
- char buf[20]; \
- int res = scnprintf(buf, sizeof(buf), "%d\n", \
- (sta->field >= 0 && \
- sta->field < mode->num_rates) ? \
- mode->rates[sta->field].rate : -1); \
- return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+#define STA_OPS(name) \
+static const struct file_operations sta_ ##name## _ops = { \
+ .read = sta_##name##_read, \
+ .open = mac80211_open_file_generic, \
}
-#define STA_OPS(name) \
+#define STA_OPS_WR(name) \
static const struct file_operations sta_ ##name## _ops = { \
.read = sta_##name##_read, \
+ .write = sta_##name##_write, \
.open = mac80211_open_file_generic, \
}
STA_OPS(name)
STA_FILE(aid, aid, D);
-STA_FILE(dev, dev->name, S);
+STA_FILE(dev, sdata->dev->name, S);
STA_FILE(rx_packets, rx_packets, LU);
STA_FILE(tx_packets, tx_packets, LU);
STA_FILE(rx_bytes, rx_bytes, LU);
STA_FILE(rx_dropped, rx_dropped, LU);
STA_FILE(tx_fragments, tx_fragments, LU);
STA_FILE(tx_filtered, tx_filtered_count, LU);
-STA_FILE(txrate, txrate, RATE);
-STA_FILE(last_txrate, last_txrate, RATE);
STA_FILE(tx_retry_failed, tx_retry_failed, LU);
STA_FILE(tx_retry_count, tx_retry_count, LU);
STA_FILE(last_rssi, last_rssi, D);
STA_FILE(last_signal, last_signal, D);
STA_FILE(last_noise, last_noise, D);
STA_FILE(channel_use, channel_use, D);
-STA_FILE(wep_weak_iv_count, wep_weak_iv_count, D);
+STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
char buf[100];
struct sta_info *sta = file->private_data;
- int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
+ int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
sta->flags & WLAN_STA_PS ? "PS\n" : "",
- sta->flags & WLAN_STA_TIM ? "TIM\n" : "",
- sta->flags & WLAN_STA_PERM ? "PERM\n" : "",
sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
sta->flags & WLAN_STA_WME ? "WME\n" : "",
}
STA_OPS(num_ps_buf_frames);
-static ssize_t sta_last_ack_rssi_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- char buf[100];
- struct sta_info *sta = file->private_data;
- int res = scnprintf(buf, sizeof(buf), "%d %d %d\n",
- sta->last_ack_rssi[0],
- sta->last_ack_rssi[1],
- sta->last_ack_rssi[2]);
- return simple_read_from_buffer(userbuf, count, ppos, buf, res);
-}
-STA_OPS(last_ack_rssi);
-
-static ssize_t sta_last_ack_ms_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- char buf[20];
- struct sta_info *sta = file->private_data;
- int res = scnprintf(buf, sizeof(buf), "%d\n",
- sta->last_ack ?
- jiffies_to_msecs(jiffies - sta->last_ack) : -1);
- return simple_read_from_buffer(userbuf, count, ppos, buf, res);
-}
-STA_OPS(last_ack_ms);
-
static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
STA_OPS(wme_tx_queue);
#endif
+static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[768], *p = buf;
+ int i;
+ struct sta_info *sta = file->private_data;
+ p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n");
+ p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n "
+ "TIDs info is: \n TID :",
+ (sta->ampdu_mlme.dialog_token_allocator + 1));
+ for (i = 0; i < STA_TID_NUM; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i);
+
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n RX :");
+ for (i = 0; i < STA_TID_NUM; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+ sta->ampdu_mlme.tid_rx[i].state);
+
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+ for (i = 0; i < STA_TID_NUM; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+ sta->ampdu_mlme.tid_rx[i].dialog_token);
+
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :");
+ for (i = 0; i < STA_TID_NUM; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+ sta->ampdu_mlme.tid_tx[i].state);
+
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+ for (i = 0; i < STA_TID_NUM; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+ sta->ampdu_mlme.tid_tx[i].dialog_token);
+
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :");
+ for (i = 0; i < STA_TID_NUM; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+ sta->ampdu_mlme.tid_tx[i].ssn);
+
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+
+static ssize_t sta_agg_status_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct sta_info *sta = file->private_data;
+ struct net_device *dev = sta->sdata->dev;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ u8 *da = sta->addr;
+ static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0};
+ static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1};
+ char *endp;
+ char buf[32];
+ int buf_size, rs;
+ unsigned int tid_num;
+ char state[4];
+
+ memset(buf, 0x00, sizeof(buf));
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ tid_num = simple_strtoul(buf, &endp, 0);
+ if (endp == buf)
+ return -EINVAL;
+
+ if ((tid_num >= 100) && (tid_num <= 115)) {
+ /* toggle Rx aggregation command */
+ tid_num = tid_num - 100;
+ if (tid_static_rx[tid_num] == 1) {
+ strcpy(state, "off ");
+ ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0,
+ WLAN_REASON_QSTA_REQUIRE_SETUP);
+ sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0xFF;
+ tid_static_rx[tid_num] = 0;
+ } else {
+ strcpy(state, "on ");
+ sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0x00;
+ tid_static_rx[tid_num] = 1;
+ }
+ printk(KERN_DEBUG "debugfs - try switching tid %u %s\n",
+ tid_num, state);
+ } else if ((tid_num >= 0) && (tid_num <= 15)) {
+ /* toggle Tx aggregation command */
+ if (tid_static_tx[tid_num] == 0) {
+ strcpy(state, "on ");
+ rs = ieee80211_start_tx_ba_session(hw, da, tid_num);
+ if (rs == 0)
+ tid_static_tx[tid_num] = 1;
+ } else {
+ strcpy(state, "off");
+ rs = ieee80211_stop_tx_ba_session(hw, da, tid_num, 1);
+ if (rs == 0)
+ tid_static_tx[tid_num] = 0;
+ }
+ printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n",
+ tid_num, state, rs);
+ }
+
+ return count;
+}
+STA_OPS_WR(agg_status);
+
#define DEBUGFS_ADD(name) \
sta->debugfs.name = debugfs_create_file(#name, 0444, \
sta->debugfs.dir, sta, &sta_ ##name## _ops);
void ieee80211_sta_debugfs_add(struct sta_info *sta)
{
struct dentry *stations_dir = sta->local->debugfs.stations;
- DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mbuf);
+ u8 *mac;
if (!stations_dir)
return;
- print_mac(mac, sta->addr);
+ mac = print_mac(mbuf, sta->addr);
sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
if (!sta->debugfs.dir)
DEBUGFS_ADD(flags);
DEBUGFS_ADD(num_ps_buf_frames);
- DEBUGFS_ADD(last_ack_rssi);
- DEBUGFS_ADD(last_ack_ms);
DEBUGFS_ADD(inactive_ms);
DEBUGFS_ADD(last_seq_ctrl);
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
DEBUGFS_ADD(wme_rx_queue);
DEBUGFS_ADD(wme_tx_queue);
#endif
+ DEBUGFS_ADD(agg_status);
}
void ieee80211_sta_debugfs_remove(struct sta_info *sta)
{
DEBUGFS_DEL(flags);
DEBUGFS_DEL(num_ps_buf_frames);
- DEBUGFS_DEL(last_ack_rssi);
- DEBUGFS_DEL(last_ack_ms);
DEBUGFS_DEL(inactive_ms);
DEBUGFS_DEL(last_seq_ctrl);
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
DEBUGFS_DEL(wme_rx_queue);
DEBUGFS_DEL(wme_tx_queue);
#endif
+ DEBUGFS_DEL(agg_status);
debugfs_remove(sta->debugfs.dir);
sta->debugfs.dir = NULL;
#ifndef __MAC80211_DEBUGFS_STA_H
#define __MAC80211_DEBUGFS_STA_H
+#include "sta_info.h"
+
#ifdef CONFIG_MAC80211_DEBUGFS
void ieee80211_sta_debugfs_add(struct sta_info *sta);
void ieee80211_sta_debugfs_remove(struct sta_info *sta);
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
+#include "mesh.h"
#include "wep.h"
#include "wme.h"
#include "aes_ccm.h"
new_flags |= FIF_ALLMULTI;
if (local->monitors)
- new_flags |= FIF_CONTROL |
- FIF_OTHER_BSS |
- FIF_BCN_PRBRESP_PROMISC;
+ new_flags |= FIF_BCN_PRBRESP_PROMISC;
+
+ if (local->fif_fcsfail)
+ new_flags |= FIF_FCSFAIL;
+
+ if (local->fif_plcpfail)
+ new_flags |= FIF_PLCPFAIL;
+
+ if (local->fif_control)
+ new_flags |= FIF_CONTROL;
+
+ if (local->fif_other_bss)
+ new_flags |= FIF_OTHER_BSS;
changed_flags = local->filter_flags ^ new_flags;
static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
{
+ int meshhdrlen;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0;
+
/* FIX: what would be proper limits for MTU?
* This interface uses 802.3 frames. */
- if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
+ if (new_mtu < 256 ||
+ new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
printk(KERN_WARNING "%s: invalid MTU %d\n",
dev->name, new_mtu);
return -EINVAL;
struct ieee80211_if_init_conf conf;
int res;
bool need_hw_reconfig = 0;
+ struct sta_info *sta;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
list_for_each_entry(nsdata, &local->interfaces, list) {
struct net_device *ndev = nsdata->dev;
- if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
- compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) {
+ if (ndev != dev && ndev != local->mdev && netif_running(ndev)) {
+ /*
+ * Allow only a single IBSS interface to be up at any
+ * time. This is restricted because beacon distribution
+ * cannot work properly if both are in the same IBSS.
+ *
+ * To remove this restriction we'd have to disallow them
+ * from setting the same SSID on different IBSS interfaces
+ * belonging to the same hardware. Then, however, we're
+ * faced with having to adopt two different TSF timers...
+ */
+ if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+ nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+ return -EBUSY;
+
+ /*
+ * Disallow multiple IBSS/STA mode interfaces.
+ *
+ * This is a technical restriction, it is possible although
+ * most likely not IEEE 802.11 compliant to have multiple
+ * STAs with just a single hardware (the TSF timer will not
+ * be adjusted properly.)
+ *
+ * However, because mac80211 uses the master device's BSS
+ * information for each STA/IBSS interface, doing this will
+ * currently corrupt that BSS information completely, unless,
+ * a not very useful case, both STAs are associated to the
+ * same BSS.
+ *
+ * To remove this restriction, the BSS information needs to
+ * be embedded in the STA/IBSS mode sdata instead of using
+ * the master device's BSS structure.
+ */
+ if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+ sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+ (nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
+ nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
+ return -EBUSY;
+
+ /*
+ * The remaining checks are only performed for interfaces
+ * with the same MAC address.
+ */
+ if (compare_ether_addr(dev->dev_addr, ndev->dev_addr))
+ continue;
+
/*
* check whether it may have the same address
*/
* can only add VLANs to enabled APs
*/
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
- nsdata->vif.type == IEEE80211_IF_TYPE_AP &&
- netif_running(nsdata->dev))
+ nsdata->vif.type == IEEE80211_IF_TYPE_AP)
sdata->u.vlan.ap = nsdata;
}
}
case IEEE80211_IF_TYPE_WDS:
if (is_zero_ether_addr(sdata->u.wds.remote_addr))
return -ENOLINK;
+
+ /* Create STA entry for the WDS peer */
+ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
+ GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
+
+ sta->flags |= WLAN_STA_AUTHORIZED;
+
+ res = sta_info_insert(sta);
+ if (res) {
+ sta_info_destroy(sta);
+ return res;
+ }
break;
case IEEE80211_IF_TYPE_VLAN:
if (!sdata->u.vlan.ap)
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_IBSS:
+ case IEEE80211_IF_TYPE_MESH_POINT:
/* no special treatment */
break;
case IEEE80211_IF_TYPE_INVALID:
/* no need to tell driver */
break;
case IEEE80211_IF_TYPE_MNTR:
+ if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+ local->cooked_mntrs++;
+ break;
+ }
+
/* must be before the call to ieee80211_configure_filter */
local->monitors++;
- if (local->monitors == 1) {
- netif_tx_lock_bh(local->mdev);
- ieee80211_configure_filter(local);
- netif_tx_unlock_bh(local->mdev);
-
+ if (local->monitors == 1)
local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
- }
+
+ if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+ local->fif_fcsfail++;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+ local->fif_plcpfail++;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+ local->fif_control++;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+ local->fif_other_bss++;
+
+ netif_tx_lock_bh(local->mdev);
+ ieee80211_configure_filter(local);
+ netif_tx_unlock_bh(local->mdev);
break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
static int ieee80211_stop(struct net_device *dev)
{
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_if_init_conf conf;
struct sta_info *sta;
int i;
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ /*
+ * Stop TX on this interface first.
+ */
+ netif_stop_queue(dev);
+
+ /*
+ * Now delete all active aggregation sessions.
+ */
+ rcu_read_lock();
- list_for_each_entry(sta, &local->sta_list, list) {
- if (sta->dev == dev)
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (sta->sdata == sdata)
for (i = 0; i < STA_TID_NUM; i++)
- ieee80211_sta_stop_rx_ba_session(sta->dev,
+ ieee80211_sta_stop_rx_ba_session(sdata->dev,
sta->addr, i,
WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_LEAVE_QBSS);
}
- netif_stop_queue(dev);
+ rcu_read_unlock();
+
+ /*
+ * Remove all stations associated with this interface.
+ *
+ * This must be done before calling ops->remove_interface()
+ * because otherwise we can later invoke ops->sta_notify()
+ * whenever the STAs are removed, and that invalidates driver
+ * assumptions about always getting a vif pointer that is valid
+ * (because if we remove a STA after ops->remove_interface()
+ * the driver will have removed the vif info already!)
+ *
+ * We could relax this and only unlink the stations from the
+ * hash table and list but keep them on a per-sdata list that
+ * will be inserted back again when the interface is brought
+ * up again, but I don't currently see a use case for that,
+ * except with WDS which gets a STA entry created when it is
+ * brought up.
+ */
+ sta_info_flush(local, sdata);
/*
* Don't count this interface for promisc/allmulti while it
/* no need to tell driver */
break;
case IEEE80211_IF_TYPE_MNTR:
- local->monitors--;
- if (local->monitors == 0) {
- netif_tx_lock_bh(local->mdev);
- ieee80211_configure_filter(local);
- netif_tx_unlock_bh(local->mdev);
+ if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+ local->cooked_mntrs--;
+ break;
+ }
+ local->monitors--;
+ if (local->monitors == 0)
local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
- }
+
+ if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+ local->fif_fcsfail--;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+ local->fif_plcpfail--;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+ local->fif_control--;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+ local->fif_other_bss--;
+
+ netif_tx_lock_bh(local->mdev);
+ ieee80211_configure_filter(local);
+ netif_tx_unlock_bh(local->mdev);
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
sdata->u.sta.state = IEEE80211_DISABLED;
return 0;
}
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata;
+ u16 start_seq_num = 0;
+ u8 *state;
+ int ret;
+ DECLARE_MAC_BUF(mac);
+
+ if (tid >= STA_TID_NUM)
+ return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Open BA session requested for %s tid %u\n",
+ print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+ printk(KERN_DEBUG "Could not find the station\n");
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+ /* we have tried too many times, receiver does not want A-MPDU */
+ if (sta->ampdu_mlme.tid_tx[tid].addba_req_num > HT_AGG_MAX_RETRIES) {
+ ret = -EBUSY;
+ goto start_ba_exit;
+ }
+
+ state = &sta->ampdu_mlme.tid_tx[tid].state;
+ /* check if the TID is not in aggregation flow already */
+ if (*state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "BA request denied - session is not "
+ "idle on tid %u\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ret = -EAGAIN;
+ goto start_ba_exit;
+ }
+
+ /* ensure that TX flow won't interrupt us
+ * until the end of the call to requeue function */
+ spin_lock_bh(&local->mdev->queue_lock);
+
+ /* create a new queue for this aggregation */
+ ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+
+ /* case no queue is available to aggregation
+ * don't switch to aggregation */
+ if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "BA request denied - no queue available for"
+ " tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ spin_unlock_bh(&local->mdev->queue_lock);
+ goto start_ba_exit;
+ }
+ sdata = sta->sdata;
+
+ /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
+ * call back right away, it must see that the flow has begun */
+ *state |= HT_ADDBA_REQUESTED_MSK;
+
+ if (local->ops->ampdu_action)
+ ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
+ ra, tid, &start_seq_num);
+
+ if (ret) {
+ /* No need to requeue the packets in the agg queue, since we
+ * held the tx lock: no packet could be enqueued to the newly
+ * allocated queue */
+ ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "BA request denied - HW or queue unavailable"
+ " for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ spin_unlock_bh(&local->mdev->queue_lock);
+ *state = HT_AGG_STATE_IDLE;
+ goto start_ba_exit;
+ }
+
+ /* Will put all the packets in the new SW queue */
+ ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+ spin_unlock_bh(&local->mdev->queue_lock);
+
+ /* We have most probably almost emptied the legacy queue */
+ /* ieee80211_wake_queue(local_to_hw(local), ieee802_1d_to_ac[tid]); */
+
+ /* send an addBA request */
+ sta->ampdu_mlme.dialog_token_allocator++;
+ sta->ampdu_mlme.tid_tx[tid].dialog_token =
+ sta->ampdu_mlme.dialog_token_allocator;
+ sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num;
+
+ ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
+ sta->ampdu_mlme.tid_tx[tid].dialog_token,
+ sta->ampdu_mlme.tid_tx[tid].ssn,
+ 0x40, 5000);
+
+ /* activate the timer for the recipient's addBA response */
+ sta->ampdu_mlme.tid_tx[tid].addba_resp_timer.expires =
+ jiffies + ADDBA_RESP_INTERVAL;
+ add_timer(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer);
+ printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+
+start_ba_exit:
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
+
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+ u8 *ra, u16 tid,
+ enum ieee80211_back_parties initiator)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+ u8 *state;
+ int ret = 0;
+ DECLARE_MAC_BUF(mac);
+
+ if (tid >= STA_TID_NUM)
+ return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Stop a BA session requested for %s tid %u\n",
+ print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+ rcu_read_lock();
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ /* check if the TID is in aggregation */
+ state = &sta->ampdu_mlme.tid_tx[tid].state;
+ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+ if (*state != HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Try to stop Tx aggregation on"
+ " non active TID\n");
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ret = -ENOENT;
+ goto stop_BA_exit;
+ }
+
+ ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
+
+ *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
+ (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+
+ if (local->ops->ampdu_action)
+ ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
+ ra, tid, NULL);
+
+ /* case HW denied going back to legacy */
+ if (ret) {
+ WARN_ON(ret != -EBUSY);
+ *state = HT_AGG_STATE_OPERATIONAL;
+ ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+ goto stop_BA_exit;
+ }
+
+stop_BA_exit:
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
+
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+ u8 *state;
+ DECLARE_MAC_BUF(mac);
+
+ if (tid >= STA_TID_NUM) {
+ printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+ tid, STA_TID_NUM);
+ return;
+ }
+
+ rcu_read_lock();
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+ rcu_read_unlock();
+ printk(KERN_DEBUG "Could not find station: %s\n",
+ print_mac(mac, ra));
+ return;
+ }
+
+ state = &sta->ampdu_mlme.tid_tx[tid].state;
+ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+ if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+ printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
+ *state);
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ rcu_read_unlock();
+ return;
+ }
+
+ WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+
+ *state |= HT_ADDBA_DRV_READY_MSK;
+
+ if (*state == HT_AGG_STATE_OPERATIONAL) {
+ printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+ ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+ }
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
+
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+ u8 *state;
+ int agg_queue;
+ DECLARE_MAC_BUF(mac);
+
+ if (tid >= STA_TID_NUM) {
+ printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+ tid, STA_TID_NUM);
+ return;
+ }
+
+ printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n",
+ print_mac(mac, ra), tid);
+
+ rcu_read_lock();
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+ printk(KERN_DEBUG "Could not find station: %s\n",
+ print_mac(mac, ra));
+ rcu_read_unlock();
+ return;
+ }
+ state = &sta->ampdu_mlme.tid_tx[tid].state;
+
+ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+ printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ rcu_read_unlock();
+ return;
+ }
+
+ if (*state & HT_AGG_STATE_INITIATOR_MSK)
+ ieee80211_send_delba(sta->sdata->dev, ra, tid,
+ WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+
+ agg_queue = sta->tid_to_tx_q[tid];
+
+ /* avoid ordering issues: we are the only one that can modify
+ * the content of the qdiscs */
+ spin_lock_bh(&local->mdev->queue_lock);
+ /* remove the queue for this aggregation */
+ ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+ spin_unlock_bh(&local->mdev->queue_lock);
+
+ /* we just requeued the all the frames that were in the removed
+ * queue, and since we might miss a softirq we do netif_schedule.
+ * ieee80211_wake_queue is not used here as this queue is not
+ * necessarily stopped */
+ netif_schedule(local->mdev);
+ *state = HT_AGG_STATE_IDLE;
+ sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
+
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+ const u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_ra_tid *ra_tid;
+ struct sk_buff *skb = dev_alloc_skb(0);
+
+ if (unlikely(!skb)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: Not enough memory, "
+ "dropping start BA session", skb->dev->name);
+ return;
+ }
+ ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+ memcpy(&ra_tid->ra, ra, ETH_ALEN);
+ ra_tid->tid = tid;
+
+ skb->pkt_type = IEEE80211_ADDBA_MSG;
+ skb_queue_tail(&local->skb_queue, skb);
+ tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+ const u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_ra_tid *ra_tid;
+ struct sk_buff *skb = dev_alloc_skb(0);
+
+ if (unlikely(!skb)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: Not enough memory, "
+ "dropping stop BA session", skb->dev->name);
+ return;
+ }
+ ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+ memcpy(&ra_tid->ra, ra, ETH_ALEN);
+ ra_tid->tid = tid;
+
+ skb->pkt_type = IEEE80211_DELBA_MSG;
+ skb_queue_tail(&local->skb_queue, skb);
+ tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
+
static void ieee80211_set_multicast_list(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
dev->destructor = ieee80211_if_free;
}
-/* WDS specialties */
-
-int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct sta_info *sta;
- DECLARE_MAC_BUF(mac);
-
- if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
- return 0;
-
- /* Create STA entry for the new peer */
- sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
- if (!sta)
- return -ENOMEM;
- sta_info_put(sta);
-
- /* Remove STA entry for the old peer */
- sta = sta_info_get(local, sdata->u.wds.remote_addr);
- if (sta) {
- sta_info_free(sta);
- sta_info_put(sta);
- } else {
- printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
- "peer %s\n",
- dev->name, print_mac(mac, sdata->u.wds.remote_addr));
- }
-
- /* Update WDS link data */
- memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
-
- return 0;
-}
-
/* everything else */
static int __ieee80211_if_config(struct net_device *dev,
conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
+ } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ conf.beacon = beacon;
+ ieee80211_start_mesh(dev);
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
int ieee80211_if_config(struct net_device *dev)
{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
+ (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
+ return ieee80211_if_config_beacon(dev);
return __ieee80211_if_config(dev, NULL, NULL);
}
int ieee80211_hw_config(struct ieee80211_local *local)
{
- struct ieee80211_hw_mode *mode;
struct ieee80211_channel *chan;
int ret = 0;
- if (local->sta_sw_scanning) {
+ if (local->sta_sw_scanning)
chan = local->scan_channel;
- mode = local->scan_hw_mode;
- } else {
+ else
chan = local->oper_channel;
- mode = local->oper_hw_mode;
- }
- local->hw.conf.channel = chan->chan;
- local->hw.conf.channel_val = chan->val;
- if (!local->hw.conf.power_level) {
- local->hw.conf.power_level = chan->power_level;
- } else {
- local->hw.conf.power_level = min(chan->power_level,
- local->hw.conf.power_level);
- }
- local->hw.conf.freq = chan->freq;
- local->hw.conf.phymode = mode->mode;
- local->hw.conf.antenna_max = chan->antenna_max;
- local->hw.conf.chan = chan;
- local->hw.conf.mode = mode;
+ local->hw.conf.channel = chan;
+
+ if (!local->hw.conf.power_level)
+ local->hw.conf.power_level = chan->max_power;
+ else
+ local->hw.conf.power_level = min(chan->max_power,
+ local->hw.conf.power_level);
+
+ local->hw.conf.max_antenna_gain = chan->max_antenna_gain;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
- "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
- local->hw.conf.phymode);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
+ wiphy_name(local->hw.wiphy), chan->center_freq);
+#endif
if (local->open_count)
ret = local->ops->config(local_to_hw(local), &local->hw.conf);
struct ieee80211_ht_bss_info *req_bss_cap)
{
struct ieee80211_conf *conf = &local->hw.conf;
- struct ieee80211_hw_mode *mode = conf->mode;
+ struct ieee80211_supported_band *sband;
int i;
+ sband = local->hw.wiphy->bands[conf->channel->band];
+
/* HT is not supported */
- if (!mode->ht_info.ht_supported) {
+ if (!sband->ht_info.ht_supported) {
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
return -EOPNOTSUPP;
}
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
} else {
conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
- conf->ht_conf.cap = req_ht_cap->cap & mode->ht_info.cap;
+ conf->ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
conf->ht_conf.cap |=
- mode->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+ sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
conf->ht_bss_conf.primary_channel =
req_bss_cap->primary_channel;
conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
for (i = 0; i < SUPP_MCS_SET_LEN; i++)
conf->ht_conf.supp_mcs_set[i] =
- mode->ht_info.supp_mcs_set[i] &
+ sband->ht_info.supp_mcs_set[i] &
req_ht_cap->supp_mcs_set[i];
/* In STA mode, this gives us indication
struct sk_buff *skb;
struct ieee80211_rx_status rx_status;
struct ieee80211_tx_status *tx_status;
+ struct ieee80211_ra_tid *ra_tid;
while ((skb = skb_dequeue(&local->skb_queue)) ||
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
skb, tx_status);
kfree(tx_status);
break;
+ case IEEE80211_DELBA_MSG:
+ ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+ ieee80211_stop_tx_ba_cb(local_to_hw(local),
+ ra_tid->ra, ra_tid->tid);
+ dev_kfree_skb(skb);
+ break;
+ case IEEE80211_ADDBA_MSG:
+ ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+ ieee80211_start_tx_ba_cb(local_to_hw(local),
+ ra_tid->ra, ra_tid->tid);
+ dev_kfree_skb(skb);
+ break ;
default: /* should never get here! */
printk(KERN_ERR "%s: Unknown message type (%d)\n",
wiphy_name(local->hw.wiphy), skb->pkt_type);
}
}
+static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
+ struct sta_info *sta,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status)
+{
+ sta->tx_filtered_count++;
+
+ /*
+ * Clear the TX filter mask for this STA when sending the next
+ * packet. If the STA went to power save mode, this will happen
+ * happen when it wakes up for the next time.
+ */
+ sta->flags |= WLAN_STA_CLEAR_PS_FILT;
+
+ /*
+ * This code races in the following way:
+ *
+ * (1) STA sends frame indicating it will go to sleep and does so
+ * (2) hardware/firmware adds STA to filter list, passes frame up
+ * (3) hardware/firmware processes TX fifo and suppresses a frame
+ * (4) we get TX status before having processed the frame and
+ * knowing that the STA has gone to sleep.
+ *
+ * This is actually quite unlikely even when both those events are
+ * processed from interrupts coming in quickly after one another or
+ * even at the same time because we queue both TX status events and
+ * RX frames to be processed by a tasklet and process them in the
+ * same order that they were received or TX status last. Hence, there
+ * is no race as long as the frame RX is processed before the next TX
+ * status, which drivers can ensure, see below.
+ *
+ * Note that this can only happen if the hardware or firmware can
+ * actually add STAs to the filter list, if this is done by the
+ * driver in response to set_tim() (which will only reduce the race
+ * this whole filtering tries to solve, not completely solve it)
+ * this situation cannot happen.
+ *
+ * To completely solve this race drivers need to make sure that they
+ * (a) don't mix the irq-safe/not irq-safe TX status/RX processing
+ * functions and
+ * (b) always process RX events before TX status events if ordering
+ * can be unknown, for example with different interrupt status
+ * bits.
+ */
+ if (sta->flags & WLAN_STA_PS &&
+ skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
+ ieee80211_remove_tx_extra(local, sta->key, skb,
+ &status->control);
+ skb_queue_tail(&sta->tx_filtered, skb);
+ return;
+ }
+
+ if (!(sta->flags & WLAN_STA_PS) &&
+ !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+ /* Software retry the packet once */
+ status->control.flags |= IEEE80211_TXCTL_REQUEUE;
+ ieee80211_remove_tx_extra(local, sta->key, skb,
+ &status->control);
+ dev_queue_xmit(skb);
+ return;
+ }
+
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: dropped TX filtered frame, "
+ "queue_len=%d PS=%d @%lu\n",
+ wiphy_name(local->hw.wiphy),
+ skb_queue_len(&sta->tx_filtered),
+ !!(sta->flags & WLAN_STA_PS), jiffies);
+ dev_kfree_skb(skb);
+}
+
void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_status *status)
{
u16 frag, type;
struct ieee80211_tx_status_rtap_hdr *rthdr;
struct ieee80211_sub_if_data *sdata;
- int monitors;
+ struct net_device *prev_dev = NULL;
if (!status) {
printk(KERN_ERR
return;
}
+ rcu_read_lock();
+
if (status->excessive_retries) {
struct sta_info *sta;
sta = sta_info_get(local, hdr->addr1);
if (sta) {
if (sta->flags & WLAN_STA_PS) {
- /* The STA is in power save mode, so assume
+ /*
+ * The STA is in power save mode, so assume
* that this TX packet failed because of that.
*/
status->excessive_retries = 0;
status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+ ieee80211_handle_filtered_frame(local, sta,
+ skb, status);
+ rcu_read_unlock();
+ return;
}
- sta_info_put(sta);
}
}
struct sta_info *sta;
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- sta->tx_filtered_count++;
-
- /* Clear the TX filter mask for this STA when sending
- * the next packet. If the STA went to power save mode,
- * this will happen when it is waking up for the next
- * time. */
- sta->clear_dst_mask = 1;
-
- /* TODO: Is the WLAN_STA_PS flag always set here or is
- * the race between RX and TX status causing some
- * packets to be filtered out before 80211.o gets an
- * update for PS status? This seems to be the case, so
- * no changes are likely to be needed. */
- if (sta->flags & WLAN_STA_PS &&
- skb_queue_len(&sta->tx_filtered) <
- STA_MAX_TX_BUFFER) {
- ieee80211_remove_tx_extra(local, sta->key,
- skb,
- &status->control);
- skb_queue_tail(&sta->tx_filtered, skb);
- } else if (!(sta->flags & WLAN_STA_PS) &&
- !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
- /* Software retry the packet once */
- status->control.flags |= IEEE80211_TXCTL_REQUEUE;
- ieee80211_remove_tx_extra(local, sta->key,
- skb,
- &status->control);
- dev_queue_xmit(skb);
- } else {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: dropped TX "
- "filtered frame queue_len=%d "
- "PS=%d @%lu\n",
- wiphy_name(local->hw.wiphy),
- skb_queue_len(
- &sta->tx_filtered),
- !!(sta->flags & WLAN_STA_PS),
- jiffies);
- }
- dev_kfree_skb(skb);
- }
- sta_info_put(sta);
+ ieee80211_handle_filtered_frame(local, sta, skb,
+ status);
+ rcu_read_unlock();
return;
}
} else
rate_control_tx_status(local->mdev, skb, status);
+ rcu_read_unlock();
+
ieee80211_led_tx(local, 0);
/* SNMP counters
/* this was a transmitted frame, but now we want to reuse it */
skb_orphan(skb);
- if (!local->monitors) {
+ /*
+ * This is a bit racy but we can avoid a lot of work
+ * with this test...
+ */
+ if (!local->monitors && !local->cooked_mntrs) {
dev_kfree_skb(skb);
return;
}
rthdr->data_retries = status->retry_count;
+ /* XXX: is this sufficient for BPF? */
+ skb_set_mac_header(skb, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+
rcu_read_lock();
- monitors = local->monitors;
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- /*
- * Using the monitors counter is possibly racy, but
- * if the value is wrong we simply either clone the skb
- * once too much or forget sending it to one monitor iface
- * The latter case isn't nice but fixing the race is much
- * more complicated.
- */
- if (!monitors || !skb)
- goto out;
-
if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) {
if (!netif_running(sdata->dev))
continue;
- monitors--;
- if (monitors)
+
+ if (prev_dev) {
skb2 = skb_clone(skb, GFP_ATOMIC);
- else
- skb2 = NULL;
- skb->dev = sdata->dev;
- /* XXX: is this sufficient for BPF? */
- skb_set_mac_header(skb, 0);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
- skb = skb2;
+ if (skb2) {
+ skb2->dev = prev_dev;
+ netif_rx(skb2);
+ }
+ }
+
+ prev_dev = sdata->dev;
}
}
- out:
+ if (prev_dev) {
+ skb->dev = prev_dev;
+ netif_rx(skb);
+ skb = NULL;
+ }
rcu_read_unlock();
- if (skb)
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status);
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
- struct net_device *mdev;
struct ieee80211_local *local;
- struct ieee80211_sub_if_data *sdata;
int priv_size;
struct wiphy *wiphy;
BUG_ON(!ops->configure_filter);
local->ops = ops;
- /* for now, mdev needs sub_if_data :/ */
- mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
- "wmaster%d", ether_setup);
- if (!mdev) {
- wiphy_free(wiphy);
- return NULL;
- }
-
- sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
- mdev->ieee80211_ptr = &sdata->wdev;
- sdata->wdev.wiphy = wiphy;
-
local->hw.queues = 1; /* default */
- local->mdev = mdev;
- local->rx_pre_handlers = ieee80211_rx_pre_handlers;
- local->rx_handlers = ieee80211_rx_handlers;
- local->tx_handlers = ieee80211_tx_handlers;
-
local->bridge_packets = 1;
local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
local->long_retry_limit = 4;
local->hw.conf.radio_enabled = 1;
- local->enabled_modes = ~0;
-
- INIT_LIST_HEAD(&local->modes_list);
-
INIT_LIST_HEAD(&local->interfaces);
INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
- ieee80211_rx_bss_list_init(mdev);
sta_info_init(local);
- mdev->hard_start_xmit = ieee80211_master_start_xmit;
- mdev->open = ieee80211_master_open;
- mdev->stop = ieee80211_master_stop;
- mdev->type = ARPHRD_IEEE80211;
- mdev->header_ops = &ieee80211_header_ops;
- mdev->set_multicast_list = ieee80211_master_set_multicast_list;
-
- sdata->vif.type = IEEE80211_IF_TYPE_AP;
- sdata->dev = mdev;
- sdata->local = local;
- sdata->u.ap.force_unicast_rateidx = -1;
- sdata->u.ap.max_ratectrl_rateidx = -1;
- ieee80211_if_sdata_init(sdata);
- /* no RCU needed since we're still during init phase */
- list_add_tail(&sdata->list, &local->interfaces);
-
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
(unsigned long)local);
tasklet_disable(&local->tx_pending_tasklet);
struct ieee80211_local *local = hw_to_local(hw);
const char *name;
int result;
+ enum ieee80211_band band;
+ struct net_device *mdev;
+ struct ieee80211_sub_if_data *sdata;
+
+ /*
+ * generic code guarantees at least one band,
+ * set this very early because much code assumes
+ * that hw.conf.channel is assigned
+ */
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[band];
+ if (sband) {
+ /* init channel we're on */
+ local->hw.conf.channel =
+ local->oper_channel =
+ local->scan_channel = &sband->channels[0];
+ break;
+ }
+ }
result = wiphy_register(local->hw.wiphy);
if (result < 0)
return result;
+ /* for now, mdev needs sub_if_data :/ */
+ mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+ "wmaster%d", ether_setup);
+ if (!mdev)
+ goto fail_mdev_alloc;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
+ mdev->ieee80211_ptr = &sdata->wdev;
+ sdata->wdev.wiphy = local->hw.wiphy;
+
+ local->mdev = mdev;
+
+ ieee80211_rx_bss_list_init(mdev);
+
+ mdev->hard_start_xmit = ieee80211_master_start_xmit;
+ mdev->open = ieee80211_master_open;
+ mdev->stop = ieee80211_master_stop;
+ mdev->type = ARPHRD_IEEE80211;
+ mdev->header_ops = &ieee80211_header_ops;
+ mdev->set_multicast_list = ieee80211_master_set_multicast_list;
+
+ sdata->vif.type = IEEE80211_IF_TYPE_AP;
+ sdata->dev = mdev;
+ sdata->local = local;
+ sdata->u.ap.force_unicast_rateidx = -1;
+ sdata->u.ap.max_ratectrl_rateidx = -1;
+ ieee80211_if_sdata_init(sdata);
+
+ /* no RCU needed since we're still during init phase */
+ list_add_tail(&sdata->list, &local->interfaces);
+
name = wiphy_dev(local->hw.wiphy)->driver->name;
local->hw.workqueue = create_singlethread_workqueue(name);
if (!local->hw.workqueue) {
/* add one default STA interface */
result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
- IEEE80211_IF_TYPE_STA);
+ IEEE80211_IF_TYPE_STA, NULL);
if (result)
printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
wiphy_name(local->hw.wiphy));
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
+ ieee80211_if_free(local->mdev);
+ local->mdev = NULL;
+fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
return result;
}
EXPORT_SYMBOL(ieee80211_register_hw);
-int ieee80211_register_hwmode(struct ieee80211_hw *hw,
- struct ieee80211_hw_mode *mode)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_rate *rate;
- int i;
-
- INIT_LIST_HEAD(&mode->list);
- list_add_tail(&mode->list, &local->modes_list);
-
- local->hw_modes |= (1 << mode->mode);
- for (i = 0; i < mode->num_rates; i++) {
- rate = &(mode->rates[i]);
- rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate;
- }
- ieee80211_prepare_rates(local, mode);
-
- if (!local->oper_hw_mode) {
- /* Default to this mode */
- local->hw.conf.phymode = mode->mode;
- local->oper_hw_mode = local->scan_hw_mode = mode;
- local->oper_channel = local->scan_channel = &mode->channels[0];
- local->hw.conf.mode = local->oper_hw_mode;
- local->hw.conf.chan = local->oper_channel;
- }
-
- if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED))
- ieee80211_set_default_regdomain(mode);
-
- return 0;
-}
-EXPORT_SYMBOL(ieee80211_register_hwmode);
-
void ieee80211_unregister_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata, *tmp;
- int i;
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
rate_control_deinitialize(local);
debugfs_hw_del(local);
- for (i = 0; i < NUM_IEEE80211_MODES; i++) {
- kfree(local->supp_rates[i]);
- kfree(local->basic_rates[i]);
- }
-
if (skb_queue_len(&local->skb_queue)
|| skb_queue_len(&local->skb_queue_unreliable))
printk(KERN_WARNING "%s: skb_queue not empty\n",
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
+ ieee80211_if_free(local->mdev);
+ local->mdev = NULL;
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
{
struct ieee80211_local *local = hw_to_local(hw);
- ieee80211_if_free(local->mdev);
wiphy_free(local->hw.wiphy);
}
EXPORT_SYMBOL(ieee80211_free_hw);
BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
- ret = rc80211_simple_init();
- if (ret)
- goto out;
-
ret = rc80211_pid_init();
if (ret)
- goto out_cleanup_simple;
+ goto out;
ret = ieee80211_wme_register();
if (ret) {
}
ieee80211_debugfs_netdev_init();
- ieee80211_regdomain_init();
return 0;
out_cleanup_pid:
rc80211_pid_exit();
- out_cleanup_simple:
- rc80211_simple_exit();
out:
return ret;
}
static void __exit ieee80211_exit(void)
{
- rc80211_simple_exit();
rc80211_pid_exit();
+ if (mesh_allocated)
+ ieee80211s_stop();
+
ieee80211_wme_unregister();
ieee80211_debugfs_netdev_exit();
}
u8 ssid[IEEE80211_MAX_SSID_LEN];
size_t ssid_len;
u16 capability; /* host byte order */
- int hw_mode;
- int channel;
+ enum ieee80211_band band;
int freq;
int rssi, signal, noise;
u8 *wpa_ie;
size_t wmm_ie_len;
u8 *ht_ie;
size_t ht_ie_len;
+#ifdef CONFIG_MAC80211_MESH
+ u8 *mesh_id;
+ size_t mesh_id_len;
+ u8 *mesh_cfg;
+#endif
#define IEEE80211_MAX_SUPP_RATES 32
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
u8 erp_value;
};
+static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return bss->mesh_cfg;
+#endif
+ return NULL;
+}
+
+static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return bss->mesh_id;
+#endif
+ return NULL;
+}
+
+static inline u8 bss_mesh_id_len(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return bss->mesh_id_len;
+#endif
+ return 0;
+}
+
+
+typedef unsigned __bitwise__ ieee80211_tx_result;
+#define TX_CONTINUE ((__force ieee80211_tx_result) 0u)
+#define TX_DROP ((__force ieee80211_tx_result) 1u)
+#define TX_QUEUED ((__force ieee80211_tx_result) 2u)
+
+#define IEEE80211_TX_FRAGMENTED BIT(0)
+#define IEEE80211_TX_UNICAST BIT(1)
+#define IEEE80211_TX_PS_BUFFERED BIT(2)
+#define IEEE80211_TX_PROBE_LAST_FRAG BIT(3)
+#define IEEE80211_TX_INJECTED BIT(4)
+
+struct ieee80211_tx_data {
+ struct sk_buff *skb;
+ struct net_device *dev;
+ struct ieee80211_local *local;
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+ u16 fc, ethertype;
+ struct ieee80211_key *key;
+ unsigned int flags;
+
+ struct ieee80211_tx_control *control;
+ struct ieee80211_channel *channel;
+ struct ieee80211_rate *rate;
+ /* use this rate (if set) for last fragment; rate can
+ * be set to lower rate for the first fragments, e.g.,
+ * when using CTS protection with IEEE 802.11g. */
+ struct ieee80211_rate *last_frag_rate;
+
+ /* Extra fragments (in addition to the first fragment
+ * in skb) */
+ int num_extra_frag;
+ struct sk_buff **extra_frag;
+};
+
-typedef enum {
- TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
-} ieee80211_txrx_result;
+typedef unsigned __bitwise__ ieee80211_rx_result;
+#define RX_CONTINUE ((__force ieee80211_rx_result) 0u)
+#define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u)
+#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u)
+#define RX_QUEUED ((__force ieee80211_rx_result) 3u)
-/* flags used in struct ieee80211_txrx_data.flags */
-/* whether the MSDU was fragmented */
-#define IEEE80211_TXRXD_FRAGMENTED BIT(0)
-#define IEEE80211_TXRXD_TXUNICAST BIT(1)
-#define IEEE80211_TXRXD_TXPS_BUFFERED BIT(2)
-#define IEEE80211_TXRXD_TXPROBE_LAST_FRAG BIT(3)
-#define IEEE80211_TXRXD_RXIN_SCAN BIT(4)
+#define IEEE80211_RX_IN_SCAN BIT(0)
/* frame is destined to interface currently processed (incl. multicast frames) */
-#define IEEE80211_TXRXD_RXRA_MATCH BIT(5)
-#define IEEE80211_TXRXD_TX_INJECTED BIT(6)
-#define IEEE80211_TXRXD_RX_AMSDU BIT(7)
-struct ieee80211_txrx_data {
+#define IEEE80211_RX_RA_MATCH BIT(1)
+#define IEEE80211_RX_AMSDU BIT(2)
+#define IEEE80211_RX_CMNTR_REPORTED BIT(3)
+#define IEEE80211_RX_FRAGMENTED BIT(4)
+
+struct ieee80211_rx_data {
struct sk_buff *skb;
struct net_device *dev;
struct ieee80211_local *local;
u16 fc, ethertype;
struct ieee80211_key *key;
unsigned int flags;
- union {
- struct {
- struct ieee80211_tx_control *control;
- struct ieee80211_hw_mode *mode;
- struct ieee80211_rate *rate;
- /* use this rate (if set) for last fragment; rate can
- * be set to lower rate for the first fragments, e.g.,
- * when using CTS protection with IEEE 802.11g. */
- struct ieee80211_rate *last_frag_rate;
- int last_frag_hwrate;
-
- /* Extra fragments (in addition to the first fragment
- * in skb) */
- int num_extra_frag;
- struct sk_buff **extra_frag;
- } tx;
- struct {
- struct ieee80211_rx_status *status;
- int sent_ps_buffered;
- int queue;
- int load;
- u32 tkip_iv32;
- u16 tkip_iv16;
- } rx;
- } u;
+
+ struct ieee80211_rx_status *status;
+ struct ieee80211_rate *rate;
+ int sent_ps_buffered;
+ int queue;
+ int load;
+ u32 tkip_iv32;
+ u16 tkip_iv16;
};
/* flags used in struct ieee80211_tx_packet_data.flags */
#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
#define IEEE80211_TXPD_REQUEUE BIT(2)
#define IEEE80211_TXPD_EAPOL_FRAME BIT(3)
+#define IEEE80211_TXPD_AMPDU BIT(4)
/* Stored in sk_buff->cb */
struct ieee80211_tx_packet_data {
int ifindex;
struct sk_buff *skb;
int num_extra_frag;
struct sk_buff **extra_frag;
- int last_frag_rateidx;
- int last_frag_hwrate;
struct ieee80211_rate *last_frag_rate;
unsigned int last_frag_rate_ctrl_probe;
};
-typedef ieee80211_txrx_result (*ieee80211_tx_handler)
-(struct ieee80211_txrx_data *tx);
-
-typedef ieee80211_txrx_result (*ieee80211_rx_handler)
-(struct ieee80211_txrx_data *rx);
-
struct beacon_data {
u8 *head, *tail;
int head_len, tail_len;
/* yes, this looks ugly, but guarantees that we can later use
* bitmap_empty :)
- * NB: don't ever use set_bit, use bss_tim_set/bss_tim_clear! */
+ * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
atomic_t num_sta_ps; /* number of stations in PS mode */
struct sk_buff_head ps_bc_buf;
struct list_head list;
};
+struct mesh_stats {
+ __u32 fwded_frames; /* Mesh forwarded frames */
+ __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/
+ __u32 dropped_frames_no_route; /* Not transmitted, no route found */
+ atomic_t estab_plinks;
+};
+
+#define PREQ_Q_F_START 0x1
+#define PREQ_Q_F_REFRESH 0x2
+struct mesh_preq_queue {
+ struct list_head list;
+ u8 dst[ETH_ALEN];
+ u8 flags;
+};
+
+struct mesh_config {
+ /* Timeouts in ms */
+ /* Mesh plink management parameters */
+ u16 dot11MeshRetryTimeout;
+ u16 dot11MeshConfirmTimeout;
+ u16 dot11MeshHoldingTimeout;
+ u16 dot11MeshMaxPeerLinks;
+ u8 dot11MeshMaxRetries;
+ u8 dot11MeshTTL;
+ bool auto_open_plinks;
+ /* HWMP parameters */
+ u32 dot11MeshHWMPactivePathTimeout;
+ u16 dot11MeshHWMPpreqMinInterval;
+ u16 dot11MeshHWMPnetDiameterTraversalTime;
+ u8 dot11MeshHWMPmaxPREQretries;
+ u32 path_refresh_time;
+ u16 min_discovery_timeout;
+};
+
+
/* flags used in struct ieee80211_if_sta.flags */
#define IEEE80211_STA_SSID_SET BIT(0)
#define IEEE80211_STA_BSSID_SET BIT(1)
enum {
IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
- IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
+ IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED,
+ IEEE80211_MESH_UP
} state;
struct timer_list timer;
struct work_struct work;
size_t ssid_len;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
+#ifdef CONFIG_MAC80211_MESH
+ struct timer_list mesh_path_timer;
+ u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
+ bool accepting_plinks;
+ size_t mesh_id_len;
+ /* Active Path Selection Protocol Identifier */
+ u8 mesh_pp_id[4];
+ /* Active Path Selection Metric Identifier */
+ u8 mesh_pm_id[4];
+ /* Congestion Control Mode Identifier */
+ u8 mesh_cc_id[4];
+ /* Local mesh Destination Sequence Number */
+ u32 dsn;
+ /* Last used PREQ ID */
+ u32 preq_id;
+ atomic_t mpaths;
+ /* Timestamp of last DSN update */
+ unsigned long last_dsn_update;
+ /* Timestamp of last DSN sent */
+ unsigned long last_preq;
+ struct mesh_rmc *rmc;
+ spinlock_t mesh_preq_queue_lock;
+ struct mesh_preq_queue preq_queue;
+ int preq_queue_len;
+ struct mesh_stats mshstats;
+ struct mesh_config mshcfg;
+ u8 mesh_seqnum[3];
+#endif
u16 aid;
u16 ap_capab, capab;
u8 *extra_ie; /* to be added to the end of AssocReq */
unsigned long ibss_join_req;
struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
- u32 supp_rates_bits;
+ u32 supp_rates_bits[IEEE80211_NUM_BANDS];
int wmm_last_param_set;
+ int num_beacons; /* number of TXed beacon frames by this STA */
};
+static inline void ieee80211_if_sta_set_mesh_id(struct ieee80211_if_sta *ifsta,
+ u8 mesh_id_len, u8 *mesh_id)
+{
+#ifdef CONFIG_MAC80211_MESH
+ ifsta->mesh_id_len = mesh_id_len;
+ memcpy(ifsta->mesh_id, mesh_id, mesh_id_len);
+#endif
+}
+
+#ifdef CONFIG_MAC80211_MESH
+#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \
+ do { (sta)->mshstats.name++; } while (0)
+#else
+#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \
+ do { } while (0)
+#endif
/* flags used in struct ieee80211_sub_if_data.flags */
#define IEEE80211_SDATA_ALLMULTI BIT(0)
#define IEEE80211_SDATA_PROMISC BIT(1)
#define IEEE80211_SDATA_USERSPACE_MLME BIT(2)
+#define IEEE80211_SDATA_OPERATING_GMODE BIT(3)
struct ieee80211_sub_if_data {
struct list_head list;
unsigned int flags;
int drop_unencrypted;
+
/*
- * IEEE 802.1X Port access control in effect,
- * drop packets to/from unauthorized port
+ * basic rates of this AP or the AP we're associated to
*/
- int ieee802_1x_pac;
+ u64 basic_rates;
u16 sequence;
struct ieee80211_if_wds wds;
struct ieee80211_if_vlan vlan;
struct ieee80211_if_sta sta;
+ u32 mntr_flags;
} u;
int channel_use;
int channel_use_raw;
struct {
struct dentry *channel_use;
struct dentry *drop_unencrypted;
- struct dentry *ieee802_1x_pac;
struct dentry *state;
struct dentry *bssid;
struct dentry *prev_bssid;
struct dentry *auth_alg;
struct dentry *auth_transaction;
struct dentry *flags;
+ struct dentry *num_beacons_sta;
} sta;
struct {
struct dentry *channel_use;
struct dentry *drop_unencrypted;
- struct dentry *ieee802_1x_pac;
struct dentry *num_sta_ps;
struct dentry *dtim_count;
struct dentry *num_beacons;
struct {
struct dentry *channel_use;
struct dentry *drop_unencrypted;
- struct dentry *ieee802_1x_pac;
struct dentry *peer;
} wds;
struct {
struct dentry *channel_use;
struct dentry *drop_unencrypted;
- struct dentry *ieee802_1x_pac;
} vlan;
struct {
struct dentry *mode;
} monitor;
struct dentry *default_key;
} debugfs;
+
+#ifdef CONFIG_MAC80211_MESH
+ struct dentry *mesh_stats_dir;
+ struct {
+ struct dentry *fwded_frames;
+ struct dentry *dropped_frames_ttl;
+ struct dentry *dropped_frames_no_route;
+ struct dentry *estab_plinks;
+ struct timer_list mesh_path_timer;
+ } mesh_stats;
+
+ struct dentry *mesh_config_dir;
+ struct {
+ struct dentry *dot11MeshRetryTimeout;
+ struct dentry *dot11MeshConfirmTimeout;
+ struct dentry *dot11MeshHoldingTimeout;
+ struct dentry *dot11MeshMaxRetries;
+ struct dentry *dot11MeshTTL;
+ struct dentry *auto_open_plinks;
+ struct dentry *dot11MeshMaxPeerLinks;
+ struct dentry *dot11MeshHWMPactivePathTimeout;
+ struct dentry *dot11MeshHWMPpreqMinInterval;
+ struct dentry *dot11MeshHWMPnetDiameterTraversalTime;
+ struct dentry *dot11MeshHWMPmaxPREQretries;
+ struct dentry *path_refresh_time;
+ struct dentry *min_discovery_timeout;
+ } mesh_config;
+#endif
+
#endif
/* must be last, dynamically sized area in this! */
struct ieee80211_vif vif;
enum {
IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2,
+ IEEE80211_DELBA_MSG = 3,
+ IEEE80211_ADDBA_MSG = 4,
};
struct ieee80211_local {
const struct ieee80211_ops *ops;
- /* List of registered struct ieee80211_hw_mode */
- struct list_head modes_list;
-
struct net_device *mdev; /* wmaster# - "master" 802.11 device */
int open_count;
- int monitors;
+ int monitors, cooked_mntrs;
+ /* number of interfaces with corresponding FIF_ flags */
+ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
u8 wstats_flags;
+ bool tim_in_locked_section; /* see ieee80211_beacon_get() */
int tx_headroom; /* required headroom for hardware/radiotap */
enum {
struct sk_buff_head skb_queue;
struct sk_buff_head skb_queue_unreliable;
- /* Station data structures */
- rwlock_t sta_lock; /* protects STA data structures */
- int num_sta; /* number of stations in sta_list */
+ /* Station data */
+ /*
+ * The lock only protects the list, hash, timer and counter
+ * against manipulation, reads are done in RCU. Additionally,
+ * the lock protects each BSS's TIM bitmap and a few items
+ * in a STA info structure.
+ */
+ spinlock_t sta_lock;
+ unsigned long num_sta;
struct list_head sta_list;
struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;
- unsigned long state[NUM_TX_DATA_QUEUES];
- struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
+ unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
+ struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
struct tasklet_struct tx_pending_tasklet;
/* number of interfaces with corresponding IFF_ flags */
struct rate_control_ref *rate_ctrl;
- /* Supported and basic rate filters for different modes. These are
- * pointers to -1 terminated lists and rates in 100 kbps units. */
- int *supp_rates[NUM_IEEE80211_MODES];
- int *basic_rates[NUM_IEEE80211_MODES];
-
int rts_threshold;
int fragmentation_threshold;
int short_retry_limit; /* dot11ShortRetryLimit */
* deliver multicast frames both back to wireless
* media and to the local net stack */
- ieee80211_rx_handler *rx_pre_handlers;
- ieee80211_rx_handler *rx_handlers;
- ieee80211_tx_handler *tx_handlers;
-
struct list_head interfaces;
bool sta_sw_scanning;
bool sta_hw_scanning;
int scan_channel_idx;
+ enum ieee80211_band scan_band;
+
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
unsigned long last_scan_completed;
struct delayed_work scan_work;
struct net_device *scan_dev;
struct ieee80211_channel *oper_channel, *scan_channel;
- struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
struct list_head sta_bss_list;
int wifi_wme_noack_test;
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
- unsigned int enabled_modes; /* bitfield of allowed modes;
- * (1 << MODE_*) */
- unsigned int hw_modes; /* bitfield of supported hardware modes;
- * (1 << MODE_*) */
-
#ifdef CONFIG_MAC80211_DEBUGFS
struct local_debugfsdentries {
- struct dentry *channel;
struct dentry *frequency;
struct dentry *antenna_sel_tx;
struct dentry *antenna_sel_rx;
struct dentry *short_retry_limit;
struct dentry *long_retry_limit;
struct dentry *total_ps_buffered;
- struct dentry *mode;
struct dentry *wep_iv;
- struct dentry *modes;
struct dentry *statistics;
struct local_debugfsdentries_statsdentries {
struct dentry *transmitted_fragment_count;
#endif
};
+/* this struct represents 802.11n's RA/TID combination */
+struct ieee80211_ra_tid {
+ u8 ra[ETH_ALEN];
+ u16 tid;
+};
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+ /* pointers to IEs */
+ u8 *ssid;
+ u8 *supp_rates;
+ u8 *fh_params;
+ u8 *ds_params;
+ u8 *cf_params;
+ u8 *tim;
+ u8 *ibss_params;
+ u8 *challenge;
+ u8 *wpa;
+ u8 *rsn;
+ u8 *erp_info;
+ u8 *ext_supp_rates;
+ u8 *wmm_info;
+ u8 *wmm_param;
+ u8 *ht_cap_elem;
+ u8 *ht_info_elem;
+ u8 *mesh_config;
+ u8 *mesh_id;
+ u8 *peer_link;
+ u8 *preq;
+ u8 *prep;
+ u8 *perr;
+
+ /* length of them, respectively */
+ u8 ssid_len;
+ u8 supp_rates_len;
+ u8 fh_params_len;
+ u8 ds_params_len;
+ u8 cf_params_len;
+ u8 tim_len;
+ u8 ibss_params_len;
+ u8 challenge_len;
+ u8 wpa_len;
+ u8 rsn_len;
+ u8 erp_info_len;
+ u8 ext_supp_rates_len;
+ u8 wmm_info_len;
+ u8 wmm_param_len;
+ u8 ht_cap_elem_len;
+ u8 ht_info_elem_len;
+ u8 mesh_config_len;
+ u8 mesh_id_len;
+ u8 peer_link_len;
+ u8 preq_len;
+ u8 prep_len;
+ u8 perr_len;
+};
+
static inline struct ieee80211_local *hw_to_local(
struct ieee80211_hw *hw)
{
ssize_t (*store)(struct sta_info *, const char *buf, size_t count);
};
-static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
-{
- /*
- * This format has been mandated by the IEEE specifications,
- * so this line may not be changed to use the __set_bit() format.
- */
- bss->tim[aid / 8] |= (1 << (aid % 8));
-}
-
-static inline void bss_tim_set(struct ieee80211_local *local,
- struct ieee80211_if_ap *bss, u16 aid)
-{
- read_lock_bh(&local->sta_lock);
- __bss_tim_set(bss, aid);
- read_unlock_bh(&local->sta_lock);
-}
-
-static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
-{
- /*
- * This format has been mandated by the IEEE specifications,
- * so this line may not be changed to use the __clear_bit() format.
- */
- bss->tim[aid / 8] &= ~(1 << (aid % 8));
-}
-
-static inline void bss_tim_clear(struct ieee80211_local *local,
- struct ieee80211_if_ap *bss, u16 aid)
-{
- read_lock_bh(&local->sta_lock);
- __bss_tim_clear(bss, aid);
- read_unlock_bh(&local->sta_lock);
-}
-
-/**
- * ieee80211_is_erp_rate - Check if a rate is an ERP rate
- * @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
- * @rate: Transmission rate to check, in 100 kbps
- *
- * Check if a given rate is an Extended Rate PHY (ERP) rate.
- */
-static inline int ieee80211_is_erp_rate(int phymode, int rate)
-{
- if (phymode == MODE_IEEE80211G) {
- if (rate != 10 && rate != 20 &&
- rate != 55 && rate != 110)
- return 1;
- }
- return 0;
-}
-
static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
{
return compare_ether_addr(raddr, addr) == 0 ||
int ieee80211_hw_config(struct ieee80211_local *local);
int ieee80211_if_config(struct net_device *dev);
int ieee80211_if_config_beacon(struct net_device *dev);
-void ieee80211_prepare_rates(struct ieee80211_local *local,
- struct ieee80211_hw_mode *mode);
-void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
-int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
+void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
void ieee80211_if_setup(struct net_device *dev);
-struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
- int phymode, int hwrate);
int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_ht_info *req_ht_cap,
struct ieee80211_ht_bss_info *req_bss_cap);
/* ieee80211_ioctl.c */
int ieee80211_set_compression(struct ieee80211_local *local,
struct net_device *dev, struct sta_info *sta);
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
+int ieee80211_set_freq(struct ieee80211_local *local, int freq);
/* ieee80211_sta.c */
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
void ieee80211_sta_timer(unsigned long data);
void ieee80211_sta_work(struct work_struct *work);
void ieee80211_sta_scan_work(struct work_struct *work);
void ieee80211_sta_req_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta);
int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
-ieee80211_txrx_result ieee80211_sta_rx_scan(struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status);
+ieee80211_rx_result ieee80211_sta_rx_scan(
+ struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status);
void ieee80211_rx_bss_list_init(struct net_device *dev);
void ieee80211_rx_bss_list_deinit(struct net_device *dev);
int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
int ieee80211_ht_addt_info_ie_to_ht_bss_info(
struct ieee80211_ht_addt_info *ht_add_info_ie,
struct ieee80211_ht_bss_info *bss_info);
+void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
+ u16 tid, u8 dialog_token, u16 start_seq_num,
+ u16 agg_size, u16 timeout);
+void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+ u16 initiator, u16 reason_code);
void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
u16 tid, u16 initiator, u16 reason);
void sta_rx_agg_session_timer_expired(unsigned long data);
+void sta_addba_resp_timer_expired(unsigned long data);
+u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+ struct ieee802_11_elems *elems,
+ enum ieee80211_band band);
+void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
+ int encrypt);
+void ieee802_11_parse_elems(u8 *start, size_t len,
+ struct ieee802_11_elems *elems);
+
+#ifdef CONFIG_MAC80211_MESH
+void ieee80211_start_mesh(struct net_device *dev);
+#else
+static inline void ieee80211_start_mesh(struct net_device *dev)
+{}
+#endif
+
/* ieee80211_iface.c */
int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev, int type);
+ struct net_device **new_dev, int type,
+ struct vif_params *params);
void ieee80211_if_set_type(struct net_device *dev, int type);
void ieee80211_if_reinit(struct net_device *dev);
void __ieee80211_if_del(struct ieee80211_local *local,
void ieee80211_if_free(struct net_device *dev);
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
-/* regdomain.c */
-void ieee80211_regdomain_init(void);
-void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode);
-
-/* rx handling */
-extern ieee80211_rx_handler ieee80211_rx_pre_handlers[];
-extern ieee80211_rx_handler ieee80211_rx_handlers[];
-
/* tx handling */
-extern ieee80211_tx_handler ieee80211_tx_handlers[];
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
void ieee80211_tx_pending(unsigned long data);
int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
#include "ieee80211_i.h"
#include "sta_info.h"
#include "debugfs_netdev.h"
+#include "mesh.h"
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
{
/* Must be called with rtnl lock held. */
int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev, int type)
+ struct net_device **new_dev, int type,
+ struct vif_params *params)
{
struct net_device *ndev;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
ieee80211_debugfs_add_netdev(sdata);
ieee80211_if_set_type(ndev, type);
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
+ params && params->mesh_id_len)
+ ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+ params->mesh_id_len,
+ params->mesh_id);
+
/* we're under RTNL so all this is fine */
if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
__ieee80211_if_del(local, sdata);
sdata->bss = NULL;
sdata->vif.type = type;
+ sdata->basic_rates = 0;
+
switch (type) {
case IEEE80211_IF_TYPE_WDS:
/* nothing special */
sdata->bss = &sdata->u.ap;
INIT_LIST_HEAD(&sdata->u.ap.vlans);
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS: {
struct ieee80211_sub_if_data *msdata;
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap;
+
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_mesh_init_sdata(sdata);
break;
}
case IEEE80211_IF_TYPE_MNTR:
dev->type = ARPHRD_IEEE80211_RADIOTAP;
dev->hard_start_xmit = ieee80211_monitor_start_xmit;
+ sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
+ MONITOR_FLAG_OTHER_BSS;
break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
- dev->name, __FUNCTION__, type);
+ dev->name, __func__, type);
}
ieee80211_debugfs_change_if_type(sdata, oldtype);
}
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct sta_info *sta;
struct sk_buff *skb;
+ int flushed;
ASSERT_RTNL();
ieee80211_if_sdata_deinit(sdata);
+ /* Need to handle mesh specially to allow eliding the function call */
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_rmc_free(dev);
+
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_INVALID:
/* cannot happen */
/* Remove all virtual interfaces that use this BSS
* as their sdata->bss */
struct ieee80211_sub_if_data *tsdata, *n;
+ struct beacon_data *beacon;
list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
}
}
- kfree(sdata->u.ap.beacon);
+ beacon = sdata->u.ap.beacon;
+ rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+ synchronize_rcu();
+ kfree(beacon);
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
local->total_ps_buffered--;
break;
}
case IEEE80211_IF_TYPE_WDS:
- sta = sta_info_get(local, sdata->u.wds.remote_addr);
- if (sta) {
- sta_info_free(sta);
- sta_info_put(sta);
- } else {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Someone had deleted my STA "
- "entry for the WDS link\n", dev->name);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
- }
+ /* nothing to do */
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
kfree(sdata->u.sta.extra_ie);
break;
}
- /* remove all STAs that are bound to this virtual interface */
- sta_info_flush(local, dev);
+ flushed = sta_info_flush(local, sdata);
+ WARN_ON(flushed);
memset(&sdata->u, 0, sizeof(sdata->u));
ieee80211_if_sdata_init(sdata);
size_t key_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- int ret = 0;
struct sta_info *sta;
struct ieee80211_key *key;
struct ieee80211_sub_if_data *sdata;
return -EINVAL;
}
- if (is_broadcast_ether_addr(sta_addr)) {
- sta = NULL;
- key = sdata->keys[idx];
- } else {
- set_tx_key = 0;
- /*
- * According to the standard, the key index of a pairwise
- * key must be zero. However, some AP are broken when it
- * comes to WEP key indices, so we work around this.
- */
- if (idx != 0 && alg != ALG_WEP) {
- printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
- "individual key\n", dev->name);
- return -EINVAL;
+ if (remove) {
+ if (is_broadcast_ether_addr(sta_addr)) {
+ key = sdata->keys[idx];
+ } else {
+ sta = sta_info_get(local, sta_addr);
+ if (!sta)
+ return -ENOENT;
+ key = sta->key;
}
- sta = sta_info_get(local, sta_addr);
- if (!sta) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
- "%s\n",
- dev->name, print_mac(mac, sta_addr));
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-
+ if (!key)
return -ENOENT;
- }
- key = sta->key;
- }
-
- if (remove) {
ieee80211_key_free(key);
- key = NULL;
+ return 0;
} else {
- /*
- * Automatically frees any old key if present.
- */
- key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
- if (!key) {
- ret = -ENOMEM;
- goto err_out;
+ key = ieee80211_key_alloc(alg, idx, key_len, _key);
+ if (!key)
+ return -ENOMEM;
+
+ sta = NULL;
+
+ if (!is_broadcast_ether_addr(sta_addr)) {
+ set_tx_key = 0;
+ /*
+ * According to the standard, the key index of a
+ * pairwise key must be zero. However, some AP are
+ * broken when it comes to WEP key indices, so we
+ * work around this.
+ */
+ if (idx != 0 && alg != ALG_WEP) {
+ ieee80211_key_free(key);
+ return -EINVAL;
+ }
+
+ sta = sta_info_get(local, sta_addr);
+ if (!sta) {
+ ieee80211_key_free(key);
+ return -ENOENT;
+ }
}
- }
- if (set_tx_key || (!sta && !sdata->default_key && key))
- ieee80211_set_default_key(sdata, idx);
+ ieee80211_key_link(key, sdata, sta);
- ret = 0;
- err_out:
- if (sta)
- sta_info_put(sta);
- return ret;
+ if (set_tx_key || (!sta && !sdata->default_key && key))
+ ieee80211_set_default_key(sdata, idx);
+ }
+
+ return 0;
}
static int ieee80211_ioctl_siwgenie(struct net_device *dev,
struct iw_request_info *info,
char *name, char *extra)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- switch (local->hw.conf.phymode) {
- case MODE_IEEE80211A:
- strcpy(name, "IEEE 802.11a");
- break;
- case MODE_IEEE80211B:
- strcpy(name, "IEEE 802.11b");
- break;
- case MODE_IEEE80211G:
- strcpy(name, "IEEE 802.11g");
- break;
- default:
- strcpy(name, "IEEE 802.11");
- break;
- }
+ strcpy(name, "IEEE 802.11");
return 0;
}
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iw_range *range = (struct iw_range *) extra;
- struct ieee80211_hw_mode *mode = NULL;
+ enum ieee80211_band band;
int c = 0;
data->length = sizeof(struct iw_range);
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
- list_for_each_entry(mode, &local->modes_list, list) {
- int i = 0;
- if (!(local->enabled_modes & (1 << mode->mode)) ||
- (local->hw_modes & local->enabled_modes &
- (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+ for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
+ int i;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[band];
+
+ if (!sband)
continue;
- while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
- struct ieee80211_channel *chan = &mode->channels[i];
+ for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
+ struct ieee80211_channel *chan = &sband->channels[i];
- if (chan->flag & IEEE80211_CHAN_W_SCAN) {
- range->freq[c].i = chan->chan;
- range->freq[c].m = chan->freq * 100000;
- range->freq[c].e = 1;
+ if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
+ range->freq[c].i =
+ ieee80211_frequency_to_channel(
+ chan->center_freq);
+ range->freq[c].m = chan->center_freq;
+ range->freq[c].e = 6;
c++;
}
- i++;
}
}
range->num_channels = c;
return 0;
}
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
+int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz)
{
- struct ieee80211_hw_mode *mode;
- int c, set = 0;
+ int set = 0;
int ret = -EINVAL;
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ int i;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
+ sband = local->hw.wiphy->bands[band];
- list_for_each_entry(mode, &local->modes_list, list) {
- if (!(local->enabled_modes & (1 << mode->mode)))
+ if (!sband)
continue;
- for (c = 0; c < mode->num_channels; c++) {
- struct ieee80211_channel *chan = &mode->channels[c];
- if (chan->flag & IEEE80211_CHAN_W_SCAN &&
- ((chan->chan == channel) || (chan->freq == freq))) {
- local->oper_channel = chan;
- local->oper_hw_mode = mode;
+
+ for (i = 0; i < sband->n_channels; i++) {
+ struct ieee80211_channel *chan = &sband->channels[i];
+
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (chan->center_freq == freqMHz) {
set = 1;
+ local->oper_channel = chan;
break;
}
}
IEEE80211_STA_AUTO_CHANNEL_SEL;
return 0;
} else
- return ieee80211_set_channel(local, freq->m, -1);
+ return ieee80211_set_freq(local,
+ ieee80211_channel_to_frequency(freq->m));
} else {
int i, div = 1000000;
for (i = 0; i < freq->e; i++)
div /= 10;
if (div > 0)
- return ieee80211_set_channel(local, -1, freq->m / div);
+ return ieee80211_set_freq(local, freq->m / div);
else
return -EINVAL;
}
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
- * driver for the current channel with firmware-based management */
-
- freq->m = local->hw.conf.freq;
+ freq->m = local->hw.conf.channel->center_freq;
freq->e = 6;
return 0;
ieee80211_sta_req_auth(dev, &sdata->u.sta);
return 0;
} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
- if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
- ETH_ALEN) == 0)
- return 0;
- return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data);
+ /*
+ * If it is necessary to update the WDS peer address
+ * while the interface is running, then we need to do
+ * more work here, namely if it is running we need to
+ * add a new and remove the old STA entry, this is
+ * normally handled by _open() and _stop().
+ */
+ if (netif_running(dev))
+ return -EBUSY;
+
+ memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
+ ETH_ALEN);
+
+ return 0;
}
return -EOPNOTSUPP;
if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
sdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EOPNOTSUPP;
struct iw_param *rate, char *extra)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
- int i;
+ int i, err = -EINVAL;
u32 target_rate = rate->value / 100000;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_supported_band *sband;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (!sdata->bss)
return -ENODEV;
- mode = local->oper_hw_mode;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
* target_rate = X, rate->fixed = 1 means only rate X
* target_rate = X, rate->fixed = 0 means all rates <= X */
sdata->bss->force_unicast_rateidx = -1;
if (rate->value < 0)
return 0;
- for (i=0; i < mode->num_rates; i++) {
- struct ieee80211_rate *rates = &mode->rates[i];
- int this_rate = rates->rate;
+
+ for (i=0; i< sband->n_bitrates; i++) {
+ struct ieee80211_rate *brate = &sband->bitrates[i];
+ int this_rate = brate->bitrate;
if (target_rate == this_rate) {
sdata->bss->max_ratectrl_rateidx = i;
if (rate->fixed)
sdata->bss->force_unicast_rateidx = i;
- return 0;
+ err = 0;
+ break;
}
}
- return -EINVAL;
+ return err;
}
static int ieee80211_ioctl_giwrate(struct net_device *dev,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_supported_band *sband;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
sta = sta_info_get(local, sdata->u.sta.bssid);
else
return -EOPNOTSUPP;
if (!sta)
return -ENODEV;
- if (sta->txrate < local->oper_hw_mode->num_rates)
- rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ if (sta->txrate_idx < sband->n_bitrates)
+ rate->value = sband->bitrates[sta->txrate_idx].bitrate;
else
rate->value = 0;
- sta_info_put(sta);
+ rate->value *= 100000;
+
return 0;
}
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
bool need_reconfig = 0;
- u8 new_power_level;
+ int new_power_level;
if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
return -EINVAL;
if (data->txpower.fixed) {
new_power_level = data->txpower.value;
} else {
- /* Automatic power level. Get the px power from the current
- * channel. */
- struct ieee80211_channel* chan = local->oper_channel;
+ /*
+ * Automatic power level. Use maximum power for the current
+ * channel. Should be part of rate control.
+ */
+ struct ieee80211_channel* chan = local->hw.conf.channel;
if (!chan)
return -EINVAL;
- new_power_level = chan->power_level;
+ new_power_level = chan->max_power;
}
if (local->hw.conf.power_level != new_power_level) {
wstats->qual.qual = sta->last_signal;
wstats->qual.noise = sta->last_noise;
wstats->qual.updated = local->wstats_flags;
- sta_info_put(sta);
}
return wstats;
}
#include <linux/types.h>
#include <linux/list.h>
#include <linux/crypto.h>
+#include <linux/rcupdate.h>
#include <net/mac80211.h>
/* ALG_TKIP
struct ieee80211_sub_if_data;
struct sta_info;
-#define KEY_FLAG_UPLOADED_TO_HARDWARE (1<<0)
+/**
+ * enum ieee80211_internal_key_flags - internal key flags
+ *
+ * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
+ * in the hardware for TX crypto hardware acceleration.
+ * @KEY_FLAG_REMOVE_FROM_HARDWARE: Indicates to the key code that this
+ * key is present in the hardware (but it cannot be used for
+ * hardware acceleration any more!)
+ */
+enum ieee80211_internal_key_flags {
+ KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
+ KEY_FLAG_REMOVE_FROM_HARDWARE = BIT(1),
+};
struct ieee80211_key {
struct ieee80211_local *local;
struct ieee80211_key_conf conf;
};
-struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta,
- enum ieee80211_key_alg alg,
+struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
int idx,
size_t key_len,
const u8 *key_data);
+/*
+ * Insert a key into data structures (sdata, sta if necessary)
+ * to make it used, free old key.
+ */
+void ieee80211_key_link(struct ieee80211_key *key,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta);
void ieee80211_key_free(struct ieee80211_key *key);
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
}
void rate_control_get_rate(struct net_device *dev,
- struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+ struct ieee80211_supported_band *sband,
+ struct sk_buff *skb,
struct rate_selection *sel)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct rate_control_ref *ref = local->rate_ctrl;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct sta_info *sta = sta_info_get(local, hdr->addr1);
+ struct sta_info *sta;
int i;
+ rcu_read_lock();
+ sta = sta_info_get(local, hdr->addr1);
+
memset(sel, 0, sizeof(struct rate_selection));
- ref->ops->get_rate(ref->priv, dev, mode, skb, sel);
+ ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
/* Select a non-ERP backup rate. */
if (!sel->nonerp) {
- for (i = 0; i < mode->num_rates - 1; i++) {
- struct ieee80211_rate *rate = &mode->rates[i];
- if (sel->rate->rate < rate->rate)
+ for (i = 0; i < sband->n_bitrates; i++) {
+ struct ieee80211_rate *rate = &sband->bitrates[i];
+ if (sel->rate->bitrate < rate->bitrate)
break;
- if (rate_supported(sta, mode, i) &&
- !(rate->flags & IEEE80211_RATE_ERP))
+ if (rate_supported(sta, sband->band, i) &&
+ !(rate->flags & IEEE80211_RATE_ERP_G))
sel->nonerp = rate;
}
}
- if (sta)
- sta_info_put(sta);
+ rcu_read_unlock();
}
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/types.h>
+#include <linux/kref.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "sta_info.h"
+/* TODO: kdoc */
struct rate_selection {
/* Selected transmission rate */
struct ieee80211_rate *rate;
struct sk_buff *skb,
struct ieee80211_tx_status *status);
void (*get_rate)(void *priv, struct net_device *dev,
- struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+ struct ieee80211_supported_band *band,
+ struct sk_buff *skb,
struct rate_selection *sel);
void (*rate_init)(void *priv, void *priv_sta,
struct ieee80211_local *local, struct sta_info *sta);
struct rate_control_ref *rate_control_alloc(const char *name,
struct ieee80211_local *local);
void rate_control_get_rate(struct net_device *dev,
- struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+ struct ieee80211_supported_band *sband,
+ struct sk_buff *skb,
struct rate_selection *sel);
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
void rate_control_put(struct rate_control_ref *ref);
#endif
}
-static inline int
-rate_supported(struct sta_info *sta, struct ieee80211_hw_mode *mode, int index)
+static inline int rate_supported(struct sta_info *sta,
+ enum ieee80211_band band,
+ int index)
{
- return (sta == NULL || sta->supp_rates & BIT(index)) &&
- (mode->rates[index].flags & IEEE80211_RATE_SUPPORTED);
+ return (sta == NULL || sta->supp_rates[band] & BIT(index));
}
static inline int
-rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
+rate_lowest_index(struct ieee80211_local *local,
+ struct ieee80211_supported_band *sband,
struct sta_info *sta)
{
int i;
- for (i = 0; i < mode->num_rates; i++) {
- if (rate_supported(sta, mode, i))
+ for (i = 0; i < sband->n_bitrates; i++)
+ if (rate_supported(sta, sband->band, i))
return i;
- }
/* warn when we cannot find a rate. */
WARN_ON(1);
}
static inline struct ieee80211_rate *
-rate_lowest(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
+rate_lowest(struct ieee80211_local *local,
+ struct ieee80211_supported_band *sband,
struct sta_info *sta)
{
- return &mode->rates[rate_lowest_index(local, mode, sta)];
+ return &sband->bitrates[rate_lowest_index(local, sband, sta)];
}
/* Rate control algorithms */
-#if defined(RC80211_SIMPLE_COMPILE) || \
- (defined(CONFIG_MAC80211_RC_SIMPLE) && \
- !defined(CONFIG_MAC80211_RC_SIMPLE_MODULE))
-extern int rc80211_simple_init(void);
-extern void rc80211_simple_exit(void);
-#else
-static inline int rc80211_simple_init(void)
-{
- return 0;
-}
-static inline void rc80211_simple_exit(void)
-{
-}
-#endif
-
#if defined(RC80211_PID_COMPILE) || \
(defined(CONFIG_MAC80211_RC_PID) && \
!defined(CONFIG_MAC80211_RC_PID_MODULE))
#include <linux/wireless.h>
#include <linux/random.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#include <net/iw_handler.h>
#include <asm/types.h>
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
#include "ieee80211_led.h"
+#include "mesh.h"
#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_MAX_TRIES 3
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
+#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
#define IEEE80211_PROBE_INTERVAL (60 * HZ)
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
+#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
u8 *ssid, size_t ssid_len);
static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len);
static void ieee80211_rx_bss_put(struct net_device *dev,
struct ieee80211_sta_bss *bss);
struct ieee80211_if_sta *ifsta);
-/* Parsed Information Elements */
-struct ieee802_11_elems {
- /* pointers to IEs */
- u8 *ssid;
- u8 *supp_rates;
- u8 *fh_params;
- u8 *ds_params;
- u8 *cf_params;
- u8 *tim;
- u8 *ibss_params;
- u8 *challenge;
- u8 *wpa;
- u8 *rsn;
- u8 *erp_info;
- u8 *ext_supp_rates;
- u8 *wmm_info;
- u8 *wmm_param;
- u8 *ht_cap_elem;
- u8 *ht_info_elem;
- /* length of them, respectively */
- u8 ssid_len;
- u8 supp_rates_len;
- u8 fh_params_len;
- u8 ds_params_len;
- u8 cf_params_len;
- u8 tim_len;
- u8 ibss_params_len;
- u8 challenge_len;
- u8 wpa_len;
- u8 rsn_len;
- u8 erp_info_len;
- u8 ext_supp_rates_len;
- u8 wmm_info_len;
- u8 wmm_param_len;
- u8 ht_cap_elem_len;
- u8 ht_info_elem_len;
-};
-
-static void ieee802_11_parse_elems(u8 *start, size_t len,
- struct ieee802_11_elems *elems)
+void ieee802_11_parse_elems(u8 *start, size_t len,
+ struct ieee802_11_elems *elems)
{
size_t left = len;
u8 *pos = start;
elems->ht_info_elem = pos;
elems->ht_info_elem_len = elen;
break;
+ case WLAN_EID_MESH_ID:
+ elems->mesh_id = pos;
+ elems->mesh_id_len = elen;
+ break;
+ case WLAN_EID_MESH_CONFIG:
+ elems->mesh_config = pos;
+ elems->mesh_config_len = elen;
+ break;
+ case WLAN_EID_PEER_LINK:
+ elems->peer_link = pos;
+ elems->peer_link_len = elen;
+ break;
+ case WLAN_EID_PREQ:
+ elems->preq = pos;
+ elems->preq_len = elen;
+ break;
+ case WLAN_EID_PREP:
+ elems->prep = pos;
+ elems->prep_len = elen;
+ break;
+ case WLAN_EID_PERR:
+ elems->perr = pos;
+ elems->perr_len = elen;
+ break;
default:
break;
}
static int ecw2cw(int ecw)
{
- int cw = 1;
- while (ecw > 0) {
- cw <<= 1;
- ecw--;
- }
- return cw - 1;
+ return (1 << ecw) - 1;
}
static void ieee80211_sta_wmm_params(struct net_device *dev,
params.aifs = pos[0] & 0x0f;
params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
params.cw_min = ecw2cw(pos[1] & 0x0f);
- /* TXOP is in units of 32 usec; burst_time in 0.1 ms */
- params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
+ params.txop = pos[2] | (pos[3] << 8);
+#ifdef CONFIG_MAC80211_DEBUG
printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
- "cWmin=%d cWmax=%d burst=%d\n",
+ "cWmin=%d cWmax=%d txop=%d\n",
dev->name, queue, aci, acm, params.aifs, params.cw_min,
- params.cw_max, params.burst_time);
+ params.cw_max, params.txop);
+#endif
/* TODO: handle ACM (block TX, fallback to next lowest allowed
* AC for now) */
if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) {
return;
bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
- local->hw.conf.channel,
+ local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
if (bss) {
if (bss->has_erp_value)
ifsta->last_probe = jiffies;
ieee80211_led_assoc(local, assoc);
+ sdata->bss_conf.assoc = assoc;
ieee80211_bss_info_change_notify(sdata, changed);
}
ieee80211_set_associated(dev, ifsta, 0);
}
-static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
- int encrypt)
+void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
+ int encrypt)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_tx_packet_data *pkt_data;
struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, *ies;
u16 capab;
struct ieee80211_sta_bss *bss;
int wmm = 0;
+ struct ieee80211_supported_band *sband;
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
}
skb_reserve(skb, local->hw.extra_tx_headroom);
- mode = local->oper_hw_mode;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
capab = ifsta->capab;
- if (mode->mode == MODE_IEEE80211G) {
- capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
- WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+ if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
+ if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+ if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+ capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
}
- bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
+
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+ local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
if (bss) {
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
*pos++ = ifsta->ssid_len;
memcpy(pos, ifsta->ssid, ifsta->ssid_len);
- len = mode->num_rates;
+ len = sband->n_bitrates;
if (len > 8)
len = 8;
pos = skb_put(skb, len + 2);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = len;
for (i = 0; i < len; i++) {
- int rate = mode->rates[i].rate;
+ int rate = sband->bitrates[i].bitrate;
*pos++ = (u8) (rate / 5);
}
- if (mode->num_rates > len) {
- pos = skb_put(skb, mode->num_rates - len + 2);
+ if (sband->n_bitrates > len) {
+ pos = skb_put(skb, sband->n_bitrates - len + 2);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = mode->num_rates - len;
- for (i = len; i < mode->num_rates; i++) {
- int rate = mode->rates[i].rate;
+ *pos++ = sband->n_bitrates - len;
+ for (i = len; i < sband->n_bitrates; i++) {
+ int rate = sband->bitrates[i].bitrate;
*pos++ = (u8) (rate / 5);
}
}
*pos++ = 0;
}
/* wmm support is a must to HT */
- if (wmm && mode->ht_info.ht_supported) {
- __le16 tmp = cpu_to_le16(mode->ht_info.cap);
+ if (wmm && sband->ht_info.ht_supported) {
+ __le16 tmp = cpu_to_le16(sband->ht_info.cap);
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
*pos++ = WLAN_EID_HT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_ht_cap);
memset(pos, 0, sizeof(struct ieee80211_ht_cap));
memcpy(pos, &tmp, sizeof(u16));
pos += sizeof(u16);
- *pos++ = (mode->ht_info.ampdu_factor |
- (mode->ht_info.ampdu_density << 2));
- memcpy(pos, mode->ht_info.supp_mcs_set, 16);
+ /* TODO: needs a define here for << 2 */
+ *pos++ = sband->ht_info.ampdu_factor |
+ (sband->ht_info.ampdu_density << 2);
+ memcpy(pos, sband->ht_info.supp_mcs_set, 16);
}
kfree(ifsta->assocreq_ies);
if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
return 0;
- bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+ local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
if (!bss)
return 0;
ifsta->state = IEEE80211_ASSOCIATED;
+ rcu_read_lock();
+
sta = sta_info_get(local, ifsta->bssid);
if (!sta) {
printk(KERN_DEBUG "%s: No STA entry for own AP %s\n",
"range\n",
dev->name, print_mac(mac, ifsta->bssid));
disassoc = 1;
- sta_info_free(sta);
+ sta_info_unlink(&sta);
} else
ieee80211_send_probe_req(dev, ifsta->bssid,
local->scan_ssid,
ifsta->ssid_len);
}
}
- sta_info_put(sta);
}
+
+ rcu_read_unlock();
+
+ if (disassoc && sta) {
+ synchronize_rcu();
+ rtnl_lock();
+ sta_info_destroy(sta);
+ rtnl_unlock();
+ }
+
if (disassoc) {
ifsta->state = IEEE80211_DISABLED;
ieee80211_set_associated(dev, ifsta, 0);
u8 *ssid, size_t ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
+ struct ieee80211_supported_band *sband;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, *supp_rates, *esupp_rates = NULL;
supp_rates = skb_put(skb, 2);
supp_rates[0] = WLAN_EID_SUPP_RATES;
supp_rates[1] = 0;
- mode = local->oper_hw_mode;
- for (i = 0; i < mode->num_rates; i++) {
- struct ieee80211_rate *rate = &mode->rates[i];
- if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
- continue;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ struct ieee80211_rate *rate = &sband->bitrates[i];
if (esupp_rates) {
pos = skb_put(skb, 1);
esupp_rates[1]++;
pos = skb_put(skb, 1);
supp_rates[1]++;
}
- *pos = rate->rate / 5;
+ *pos = rate->bitrate / 5;
}
ieee80211_sta_tx(dev, skb, 0);
return;
}
+void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
+ u16 tid, u8 dialog_token, u16 start_seq_num,
+ u16 agg_size, u16 timeout)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ u16 capab;
+
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
+ sizeof(mgmt->u.action.u.addba_req));
+
+
+ if (!skb) {
+ printk(KERN_ERR "%s: failed to allocate buffer "
+ "for addba request frame\n", dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, da, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+ memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+ else
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+
+ skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
+
+ mgmt->u.action.category = WLAN_CATEGORY_BACK;
+ mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
+
+ mgmt->u.action.u.addba_req.dialog_token = dialog_token;
+ capab = (u16)(1 << 1); /* bit 1 aggregation policy */
+ capab |= (u16)(tid << 2); /* bit 5:2 TID number */
+ capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
+
+ mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
+
+ mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
+ mgmt->u.action.u.addba_req.start_seq_num =
+ cpu_to_le16(start_seq_num << 4);
+
+ ieee80211_sta_tx(dev, skb, 0);
+}
+
static void ieee80211_sta_process_addba_request(struct net_device *dev,
struct ieee80211_mgmt *mgmt,
size_t len)
int ret = -EOPNOTSUPP;
DECLARE_MAC_BUF(mac);
+ rcu_read_lock();
+
sta = sta_info_get(local, mgmt->sa);
- if (!sta)
+ if (!sta) {
+ rcu_read_unlock();
return;
+ }
/* extract session parameters from addba request frame */
dialog_token = mgmt->u.action.u.addba_req.dialog_token;
}
/* determine default buffer size */
if (buf_size == 0) {
- struct ieee80211_hw_mode *mode = conf->mode;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[conf->channel->band];
buf_size = IEEE80211_MIN_AMPDU_BUF;
- buf_size = buf_size << mode->ht_info.ampdu_factor;
+ buf_size = buf_size << sband->ht_info.ampdu_factor;
}
tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid];
if (local->ops->ampdu_action)
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
- sta->addr, tid, start_seq_num);
+ sta->addr, tid, &start_seq_num);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret);
#endif /* CONFIG_MAC80211_HT_DEBUG */
spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
end_no_lock:
- ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token,
- status, 1, buf_size, timeout);
- sta_info_put(sta);
+ ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
+ dialog_token, status, 1, buf_size, timeout);
+ rcu_read_unlock();
+}
+
+static void ieee80211_sta_process_addba_resp(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ struct sta_info *sta;
+ u16 capab;
+ u16 tid;
+ u8 *state;
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, mgmt->sa);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+
+ capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+
+ state = &sta->ampdu_mlme.tid_tx[tid].state;
+
+ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+ if (mgmt->u.action.u.addba_resp.dialog_token !=
+ sta->ampdu_mlme.tid_tx[tid].dialog_token) {
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ rcu_read_unlock();
+ return;
+ }
+
+ del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
+ == WLAN_STATUS_SUCCESS) {
+ if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
+ "%d\n", *state);
+ rcu_read_unlock();
+ return;
+ }
+
+ if (*state & HT_ADDBA_RECEIVED_MSK)
+ printk(KERN_DEBUG "double addBA response\n");
+
+ *state |= HT_ADDBA_RECEIVED_MSK;
+ sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
+
+ if (*state == HT_AGG_STATE_OPERATIONAL) {
+ printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
+ ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+ }
+
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
+ } else {
+ printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
+
+ sta->ampdu_mlme.tid_tx[tid].addba_req_num++;
+ /* this will allow the state check in stop_BA_session */
+ *state = HT_AGG_STATE_OPERATIONAL;
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
+ WLAN_BACK_INITIATOR);
+ }
+ rcu_read_unlock();
}
-static void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
- u16 initiator, u16 reason_code)
+void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+ u16 initiator, u16 reason_code)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
int ret, i;
+ rcu_read_lock();
+
sta = sta_info_get(local, ra);
- if (!sta)
+ if (!sta) {
+ rcu_read_unlock();
return;
+ }
/* check if TID is in operational state */
spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
if (sta->ampdu_mlme.tid_rx[tid].state
!= HT_AGG_STATE_OPERATIONAL) {
spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
- sta_info_put(sta);
+ rcu_read_unlock();
return;
}
sta->ampdu_mlme.tid_rx[tid].state =
BUG_ON(!local->ops->ampdu_action);
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
- ra, tid, EINVAL);
+ ra, tid, NULL);
if (ret)
printk(KERN_DEBUG "HW problem - can not stop rx "
"aggergation for tid %d\n", tid);
kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf);
sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE;
- sta_info_put(sta);
+ rcu_read_unlock();
}
+
static void ieee80211_sta_process_delba(struct net_device *dev,
struct ieee80211_mgmt *mgmt, size_t len)
{
u16 initiator;
DECLARE_MAC_BUF(mac);
+ rcu_read_lock();
+
sta = sta_info_get(local, mgmt->sa);
- if (!sta)
+ if (!sta) {
+ rcu_read_unlock();
return;
+ }
params = le16_to_cpu(mgmt->u.action.u.delba.params);
tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
- printk(KERN_DEBUG "delba from %s on tid %d reason code %d\n",
- print_mac(mac, mgmt->sa), tid,
+ printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
+ print_mac(mac, mgmt->sa),
+ initiator ? "recipient" : "initiator", tid,
mgmt->u.action.u.delba.reason_code);
#endif /* CONFIG_MAC80211_HT_DEBUG */
if (initiator == WLAN_BACK_INITIATOR)
ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
WLAN_BACK_INITIATOR, 0);
- sta_info_put(sta);
+ else { /* WLAN_BACK_RECIPIENT */
+ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ sta->ampdu_mlme.tid_tx[tid].state =
+ HT_AGG_STATE_OPERATIONAL;
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
+ WLAN_BACK_RECIPIENT);
+ }
+ rcu_read_unlock();
+}
+
+/*
+ * After sending add Block Ack request we activated a timer until
+ * add Block Ack response will arrive from the recipient.
+ * If this timer expires sta_addba_resp_timer_expired will be executed.
+ */
+void sta_addba_resp_timer_expired(unsigned long data)
+{
+ /* not an elegant detour, but there is no choice as the timer passes
+ * only one argument, and both sta_info and TID are needed, so init
+ * flow in sta_info_create gives the TID as data, while the timer_to_id
+ * array gives the sta through container_of */
+ u16 tid = *(int *)data;
+ struct sta_info *temp_sta = container_of((void *)data,
+ struct sta_info, timer_to_tid[tid]);
+
+ struct ieee80211_local *local = temp_sta->local;
+ struct ieee80211_hw *hw = &local->hw;
+ struct sta_info *sta;
+ u8 *state;
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, temp_sta->addr);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+
+ state = &sta->ampdu_mlme.tid_tx[tid].state;
+ /* check if the TID waits for addBA response */
+ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ *state = HT_AGG_STATE_IDLE;
+ printk(KERN_DEBUG "timer expired on tid %d but we are not "
+ "expecting addBA response there", tid);
+ goto timer_expired_exit;
+ }
+
+ printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+
+ /* go through the state check in stop_BA_session */
+ *state = HT_AGG_STATE_OPERATIONAL;
+ spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
+ WLAN_BACK_INITIATOR);
+
+timer_expired_exit:
+ rcu_read_unlock();
}
/*
{
/* not an elegant detour, but there is no choice as the timer passes
* only one argument, and verious sta_info are needed here, so init
- * flow in sta_info_add gives the TID as data, while the timer_to_id
+ * flow in sta_info_create gives the TID as data, while the timer_to_id
* array gives the sta through container_of */
u8 *ptid = (u8 *)data;
u8 *timer_to_id = ptid - *ptid;
timer_to_tid[0]);
printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
- ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid,
- WLAN_BACK_TIMER,
+ ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
+ (u16)*ptid, WLAN_BACK_TIMER,
WLAN_REASON_QSTA_TIMEOUT);
}
{
struct ieee80211_local *local = sdata->local;
struct net_device *dev = sdata->dev;
- struct ieee80211_hw_mode *mode;
+ struct ieee80211_supported_band *sband;
struct sta_info *sta;
- u32 rates;
+ u64 rates, basic_rates;
u16 capab_info, status_code, aid;
struct ieee802_11_elems elems;
struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
u8 *pos;
int i, j;
DECLARE_MAC_BUF(mac);
+ bool have_higher_than_11mbit = false;
/* AssocResp and ReassocResp have identical structure, so process both
* of them in this function. */
if (ifsta->assocresp_ies)
memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
- /* set AID, ieee80211_set_associated() will tell the driver */
- bss_conf->aid = aid;
- ieee80211_set_associated(dev, ifsta, 1);
+ rcu_read_lock();
/* Add STA entry for the AP */
sta = sta_info_get(local, ifsta->bssid);
if (!sta) {
struct ieee80211_sta_bss *bss;
- sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL);
+ int err;
+
+ sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
if (!sta) {
- printk(KERN_DEBUG "%s: failed to add STA entry for the"
- " AP\n", dev->name);
+ printk(KERN_DEBUG "%s: failed to alloc STA entry for"
+ " the AP\n", dev->name);
+ rcu_read_unlock();
return;
}
bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
- local->hw.conf.channel,
+ local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
if (bss) {
sta->last_rssi = bss->rssi;
sta->last_noise = bss->noise;
ieee80211_rx_bss_put(dev, bss);
}
+
+ err = sta_info_insert(sta);
+ if (err) {
+ printk(KERN_DEBUG "%s: failed to insert STA entry for"
+ " the AP (error %d)\n", dev->name, err);
+ sta_info_destroy(sta);
+ rcu_read_unlock();
+ return;
+ }
}
- sta->dev = dev;
- sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP;
+ /*
+ * FIXME: Do we really need to update the sta_info's information here?
+ * We already know about the AP (we found it in our list) so it
+ * should already be filled with the right info, no?
+ * As is stands, all this is racy because typically we assume
+ * the information that is filled in here (except flags) doesn't
+ * change while a STA structure is alive. As such, it should move
+ * to between the sta_info_alloc() and sta_info_insert() above.
+ */
+
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
+ WLAN_STA_AUTHORIZED;
rates = 0;
- mode = local->oper_hw_mode;
+ basic_rates = 0;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
for (i = 0; i < elems.supp_rates_len; i++) {
int rate = (elems.supp_rates[i] & 0x7f) * 5;
- for (j = 0; j < mode->num_rates; j++)
- if (mode->rates[j].rate == rate)
+
+ if (rate > 110)
+ have_higher_than_11mbit = true;
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].bitrate == rate)
rates |= BIT(j);
+ if (elems.supp_rates[i] & 0x80)
+ basic_rates |= BIT(j);
+ }
}
+
for (i = 0; i < elems.ext_supp_rates_len; i++) {
int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
- for (j = 0; j < mode->num_rates; j++)
- if (mode->rates[j].rate == rate)
+
+ if (rate > 110)
+ have_higher_than_11mbit = true;
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].bitrate == rate)
rates |= BIT(j);
+ if (elems.ext_supp_rates[i] & 0x80)
+ basic_rates |= BIT(j);
+ }
}
- sta->supp_rates = rates;
+
+ sta->supp_rates[local->hw.conf.channel->band] = rates;
+ sdata->basic_rates = basic_rates;
+
+ /* cf. IEEE 802.11 9.2.12 */
+ if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+ have_higher_than_11mbit)
+ sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+ else
+ sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
local->ops->conf_ht) {
if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
sta->flags |= WLAN_STA_WME;
+ rcu_read_unlock();
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
elems.wmm_param_len);
- }
-
+ } else
+ rcu_read_unlock();
- sta_info_put(sta);
+ /* set AID, ieee80211_set_associated() will tell the driver */
+ bss_conf->aid = aid;
+ ieee80211_set_associated(dev, ifsta, 1);
ieee80211_associated(dev, ifsta);
}
struct ieee80211_sta_bss *bss)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- bss->hnext = local->sta_bss_hash[STA_HASH(bss->bssid)];
- local->sta_bss_hash[STA_HASH(bss->bssid)] = bss;
+ u8 hash_idx;
+
+ if (bss_mesh_cfg(bss))
+ hash_idx = mesh_id_hash(bss_mesh_id(bss),
+ bss_mesh_id_len(bss));
+ else
+ hash_idx = STA_HASH(bss->bssid);
+
+ bss->hnext = local->sta_bss_hash[hash_idx];
+ local->sta_bss_hash[hash_idx] = bss;
}
static struct ieee80211_sta_bss *
-ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel,
+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
atomic_inc(&bss->users);
atomic_inc(&bss->users);
memcpy(bss->bssid, bssid, ETH_ALEN);
- bss->channel = channel;
+ bss->freq = freq;
if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
memcpy(bss->ssid, ssid, ssid_len);
bss->ssid_len = ssid_len;
return bss;
}
-
static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
spin_lock_bh(&local->sta_bss_lock);
bss = local->sta_bss_hash[STA_HASH(bssid)];
while (bss) {
- if (!memcmp(bss->bssid, bssid, ETH_ALEN) &&
- bss->channel == channel &&
+ if (!bss_mesh_cfg(bss) &&
+ !memcmp(bss->bssid, bssid, ETH_ALEN) &&
+ bss->freq == freq &&
bss->ssid_len == ssid_len &&
(ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
atomic_inc(&bss->users);
return bss;
}
+#ifdef CONFIG_MAC80211_MESH
+static struct ieee80211_sta_bss *
+ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
+ u8 *mesh_cfg, int freq)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss;
+
+ spin_lock_bh(&local->sta_bss_lock);
+ bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
+ while (bss) {
+ if (bss_mesh_cfg(bss) &&
+ !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
+ bss->freq == freq &&
+ mesh_id_len == bss->mesh_id_len &&
+ (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
+ mesh_id_len))) {
+ atomic_inc(&bss->users);
+ break;
+ }
+ bss = bss->hnext;
+ }
+ spin_unlock_bh(&local->sta_bss_lock);
+ return bss;
+}
+
+static struct ieee80211_sta_bss *
+ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
+ u8 *mesh_cfg, int freq)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss;
+
+ bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
+ if (!bss)
+ return NULL;
+
+ bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC);
+ if (!bss->mesh_cfg) {
+ kfree(bss);
+ return NULL;
+ }
+
+ if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) {
+ bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC);
+ if (!bss->mesh_id) {
+ kfree(bss->mesh_cfg);
+ kfree(bss);
+ return NULL;
+ }
+ memcpy(bss->mesh_id, mesh_id, mesh_id_len);
+ }
+
+ atomic_inc(&bss->users);
+ atomic_inc(&bss->users);
+ memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN);
+ bss->mesh_id_len = mesh_id_len;
+ bss->freq = freq;
+ spin_lock_bh(&local->sta_bss_lock);
+ /* TODO: order by RSSI? */
+ list_add_tail(&bss->list, &local->sta_bss_list);
+ __ieee80211_rx_bss_hash_add(dev, bss);
+ spin_unlock_bh(&local->sta_bss_lock);
+ return bss;
+}
+#endif
static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
{
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
+ kfree(bss_mesh_id(bss));
+ kfree(bss_mesh_cfg(bss));
kfree(bss);
}
}
-static void ieee80211_rx_bss_info(struct net_device *dev,
- struct ieee80211_mgmt *mgmt,
- size_t len,
- struct ieee80211_rx_status *rx_status,
- int beacon)
+static int ieee80211_sta_join_ibss(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_sta_bss *bss)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee802_11_elems elems;
- size_t baselen;
- int channel, clen;
- struct ieee80211_sta_bss *bss;
- struct sta_info *sta;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- u64 timestamp;
- DECLARE_MAC_BUF(mac);
- DECLARE_MAC_BUF(mac2);
+ int res, rates, i, j;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_tx_control control;
+ struct rate_selection ratesel;
+ u8 *pos;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_supported_band *sband;
- if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
- return; /* ignore ProbeResp to foreign address */
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-#if 0
- printk(KERN_DEBUG "%s: RX %s from %s to %s\n",
- dev->name, beacon ? "Beacon" : "Probe Response",
- print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
-#endif
+ /* Remove possible STA entries from other IBSS networks. */
+ sta_info_flush(local, NULL);
- baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
- if (baselen > len)
- return;
+ if (local->ops->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->ops->reset_tsf(local_to_hw(local));
+ }
+ memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
+ res = ieee80211_if_config(dev);
+ if (res)
+ return res;
- timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
+ local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
- memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- static unsigned long last_tsf_debug = 0;
- u64 tsf;
- if (local->ops->get_tsf)
- tsf = local->ops->get_tsf(local_to_hw(local));
- else
- tsf = -1LLU;
- if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
- printk(KERN_DEBUG "RX beacon SA=%s BSSID="
- "%s TSF=0x%llx BCN=0x%llx diff=%lld "
- "@%lu\n",
- print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid),
- (unsigned long long)tsf,
- (unsigned long long)timestamp,
- (unsigned long long)(tsf - timestamp),
- jiffies);
- last_tsf_debug = jiffies;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ sdata->drop_unencrypted = bss->capability &
+ WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+ res = ieee80211_set_freq(local, bss->freq);
+
+ if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
+ printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+ "%d MHz\n", dev->name, local->oper_channel->center_freq);
+ return -1;
+ }
+
+ /* Set beacon template */
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ do {
+ if (!skb)
+ break;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+ memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_BEACON);
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->u.beacon.beacon_int =
+ cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
+
+ pos = skb_put(skb, 2 + ifsta->ssid_len);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ifsta->ssid_len;
+ memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+
+ rates = bss->supp_rates_len;
+ if (rates > 8)
+ rates = 8;
+ pos = skb_put(skb, 2 + rates);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = rates;
+ memcpy(pos, bss->supp_rates, rates);
+
+ if (bss->band == IEEE80211_BAND_2GHZ) {
+ pos = skb_put(skb, 2 + 1);
+ *pos++ = WLAN_EID_DS_PARAMS;
+ *pos++ = 1;
+ *pos++ = ieee80211_frequency_to_channel(bss->freq);
}
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+ pos = skb_put(skb, 2 + 2);
+ *pos++ = WLAN_EID_IBSS_PARAMS;
+ *pos++ = 2;
+ /* FIX: set ATIM window based on scan results */
+ *pos++ = 0;
+ *pos++ = 0;
+
+ if (bss->supp_rates_len > 8) {
+ rates = bss->supp_rates_len - 8;
+ pos = skb_put(skb, 2 + rates);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = rates;
+ memcpy(pos, &bss->supp_rates[8], rates);
+ }
+
+ memset(&control, 0, sizeof(control));
+ rate_control_get_rate(dev, sband, skb, &ratesel);
+ if (!ratesel.rate) {
+ printk(KERN_DEBUG "%s: Failed to determine TX rate "
+ "for IBSS beacon\n", dev->name);
+ break;
+ }
+ control.vif = &sdata->vif;
+ control.tx_rate = ratesel.rate;
+ if (sdata->bss_conf.use_short_preamble &&
+ ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
+ control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ control.flags |= IEEE80211_TXCTL_NO_ACK;
+ control.retry_limit = 1;
+
+ ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
+ if (ifsta->probe_resp) {
+ mgmt = (struct ieee80211_mgmt *)
+ ifsta->probe_resp->data;
+ mgmt->frame_control =
+ IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_PROBE_RESP);
+ } else {
+ printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
+ "template for IBSS\n", dev->name);
+ }
+
+ if (local->ops->beacon_update &&
+ local->ops->beacon_update(local_to_hw(local),
+ skb, &control) == 0) {
+ printk(KERN_DEBUG "%s: Configured IBSS beacon "
+ "template\n", dev->name);
+ skb = NULL;
+ }
+
+ rates = 0;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+ for (j = 0; j < sband->n_bitrates; j++)
+ if (sband->bitrates[j].bitrate == bitrate)
+ rates |= BIT(j);
+ }
+ ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+ } while (0);
+
+ if (skb) {
+ printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
+ "template\n", dev->name);
+ dev_kfree_skb(skb);
}
+ ifsta->state = IEEE80211_IBSS_JOINED;
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+ ieee80211_rx_bss_put(dev, bss);
+
+ return res;
+}
+
+u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+ struct ieee802_11_elems *elems,
+ enum ieee80211_band band)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *bitrates;
+ size_t num_rates;
+ u64 supp_rates;
+ int i, j;
+ sband = local->hw.wiphy->bands[band];
+
+ if (!sband) {
+ WARN_ON(1);
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ }
+
+ bitrates = sband->bitrates;
+ num_rates = sband->n_bitrates;
+ supp_rates = 0;
+ for (i = 0; i < elems->supp_rates_len +
+ elems->ext_supp_rates_len; i++) {
+ u8 rate = 0;
+ int own_rate;
+ if (i < elems->supp_rates_len)
+ rate = elems->supp_rates[i];
+ else if (elems->ext_supp_rates)
+ rate = elems->ext_supp_rates
+ [i - elems->supp_rates_len];
+ own_rate = 5 * (rate & 0x7f);
+ for (j = 0; j < num_rates; j++)
+ if (bitrates[j].bitrate == own_rate)
+ supp_rates |= BIT(j);
+ }
+ return supp_rates;
+}
+
+
+static void ieee80211_rx_bss_info(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status,
+ int beacon)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee802_11_elems elems;
+ size_t baselen;
+ int freq, clen;
+ struct ieee80211_sta_bss *bss;
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ u64 beacon_timestamp, rx_timestamp;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
+ return; /* ignore ProbeResp to foreign address */
+
+#if 0
+ printk(KERN_DEBUG "%s: RX %s from %s to %s\n",
+ dev->name, beacon ? "Beacon" : "Probe Response",
+ print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
+#endif
+
+ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+ if (baselen > len)
+ return;
+
+ beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
+ if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id &&
+ elems.mesh_config && mesh_matches_local(&elems, dev)) {
+ u64 rates = ieee80211_sta_get_rates(local, &elems,
+ rx_status->band);
+
+ mesh_neighbour_update(mgmt->sa, rates, dev,
+ mesh_peer_accepts_plinks(&elems, dev));
+ }
+
+ rcu_read_lock();
+
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
(sta = sta_info_get(local, mgmt->sa))) {
- struct ieee80211_hw_mode *mode;
- struct ieee80211_rate *rates;
- size_t num_rates;
- u32 supp_rates, prev_rates;
- int i, j;
-
- mode = local->sta_sw_scanning ?
- local->scan_hw_mode : local->oper_hw_mode;
-
- if (local->sta_hw_scanning) {
- /* search for the correct mode matches the beacon */
- list_for_each_entry(mode, &local->modes_list, list)
- if (mode->mode == rx_status->phymode)
- break;
-
- if (mode == NULL)
- mode = local->oper_hw_mode;
- }
- rates = mode->rates;
- num_rates = mode->num_rates;
-
- supp_rates = 0;
- for (i = 0; i < elems.supp_rates_len +
- elems.ext_supp_rates_len; i++) {
- u8 rate = 0;
- int own_rate;
- if (i < elems.supp_rates_len)
- rate = elems.supp_rates[i];
- else if (elems.ext_supp_rates)
- rate = elems.ext_supp_rates
- [i - elems.supp_rates_len];
- own_rate = 5 * (rate & 0x7f);
- for (j = 0; j < num_rates; j++)
- if (rates[j].rate == own_rate)
- supp_rates |= BIT(j);
- }
+ u64 prev_rates;
+ u64 supp_rates = ieee80211_sta_get_rates(local, &elems,
+ rx_status->band);
- prev_rates = sta->supp_rates;
- sta->supp_rates &= supp_rates;
- if (sta->supp_rates == 0) {
+ prev_rates = sta->supp_rates[rx_status->band];
+ sta->supp_rates[rx_status->band] &= supp_rates;
+ if (sta->supp_rates[rx_status->band] == 0) {
/* No matching rates - this should not really happen.
* Make sure that at least one rate is marked
* supported to avoid issues with TX rate ctrl. */
- sta->supp_rates = sdata->u.sta.supp_rates_bits;
+ sta->supp_rates[rx_status->band] =
+ sdata->u.sta.supp_rates_bits[rx_status->band];
}
- if (sta->supp_rates != prev_rates) {
+ if (sta->supp_rates[rx_status->band] != prev_rates) {
printk(KERN_DEBUG "%s: updated supp_rates set for "
- "%s based on beacon info (0x%x & 0x%x -> "
- "0x%x)\n",
- dev->name, print_mac(mac, sta->addr), prev_rates,
- supp_rates, sta->supp_rates);
+ "%s based on beacon info (0x%llx & 0x%llx -> "
+ "0x%llx)\n",
+ dev->name, print_mac(mac, sta->addr),
+ (unsigned long long) prev_rates,
+ (unsigned long long) supp_rates,
+ (unsigned long long) sta->supp_rates[rx_status->band]);
}
- sta_info_put(sta);
}
- if (!elems.ssid)
- return;
+ rcu_read_unlock();
if (elems.ds_params && elems.ds_params_len == 1)
- channel = elems.ds_params[0];
+ freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
else
- channel = rx_status->channel;
+ freq = rx_status->freq;
- bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel,
- elems.ssid, elems.ssid_len);
- if (!bss) {
- bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel,
+#ifdef CONFIG_MAC80211_MESH
+ if (elems.mesh_config)
+ bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id,
+ elems.mesh_id_len, elems.mesh_config, freq);
+ else
+#endif
+ bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
elems.ssid, elems.ssid_len);
+ if (!bss) {
+#ifdef CONFIG_MAC80211_MESH
+ if (elems.mesh_config)
+ bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id,
+ elems.mesh_id_len, elems.mesh_config, freq);
+ else
+#endif
+ bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
+ elems.ssid, elems.ssid_len);
if (!bss)
return;
} else {
#endif
}
- if (bss->probe_resp && beacon) {
- /* Do not allow beacon to override data from Probe Response. */
+ bss->band = rx_status->band;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ bss->probe_resp && beacon) {
+ /* STA mode:
+ * Do not allow beacon to override data from Probe Response. */
ieee80211_rx_bss_put(dev, bss);
return;
}
bss->ht_ie_len = 0;
}
- bss->hw_mode = rx_status->phymode;
- bss->freq = rx_status->freq;
- if (channel != rx_status->channel &&
- (bss->hw_mode == MODE_IEEE80211G ||
- bss->hw_mode == MODE_IEEE80211B) &&
- channel >= 1 && channel <= 14) {
- static const int freq_list[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442,
- 2447, 2452, 2457, 2462, 2467, 2472, 2484
- };
- /* IEEE 802.11g/b mode can receive packets from neighboring
- * channels, so map the channel into frequency. */
- bss->freq = freq_list[channel - 1];
- }
- bss->timestamp = timestamp;
+ bss->timestamp = beacon_timestamp;
bss->last_update = jiffies;
bss->rssi = rx_status->ssi;
bss->signal = rx_status->signal;
bss->noise = rx_status->noise;
if (!beacon)
bss->probe_resp++;
+
+ /* check if we need to merge IBSS */
+ if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
+ !local->sta_sw_scanning && !local->sta_hw_scanning &&
+ bss->capability & WLAN_CAPABILITY_IBSS &&
+ bss->freq == local->oper_channel->center_freq &&
+ elems.ssid_len == sdata->u.sta.ssid_len &&
+ memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) {
+ if (rx_status->flag & RX_FLAG_TSFT) {
+ /* in order for correct IBSS merging we need mactime
+ *
+ * since mactime is defined as the time the first data
+ * symbol of the frame hits the PHY, and the timestamp
+ * of the beacon is defined as "the time that the data
+ * symbol containing the first bit of the timestamp is
+ * transmitted to the PHY plus the transmitting STA’s
+ * delays through its local PHY from the MAC-PHY
+ * interface to its interface with the WM"
+ * (802.11 11.1.2) - equals the time this bit arrives at
+ * the receiver - we have to take into account the
+ * offset between the two.
+ * e.g: at 1 MBit that means mactime is 192 usec earlier
+ * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
+ */
+ int rate = local->hw.wiphy->bands[rx_status->band]->
+ bitrates[rx_status->rate_idx].bitrate;
+ rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
+ } else if (local && local->ops && local->ops->get_tsf)
+ /* second best option: get current TSF */
+ rx_timestamp = local->ops->get_tsf(local_to_hw(local));
+ else
+ /* can't merge without knowing the TSF */
+ rx_timestamp = -1LLU;
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG "RX beacon SA=%s BSSID="
+ "%s TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+ print_mac(mac, mgmt->sa),
+ print_mac(mac2, mgmt->bssid),
+ (unsigned long long)rx_timestamp,
+ (unsigned long long)beacon_timestamp,
+ (unsigned long long)(rx_timestamp - beacon_timestamp),
+ jiffies);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ if (beacon_timestamp > rx_timestamp) {
+#ifndef CONFIG_MAC80211_IBSS_DEBUG
+ if (net_ratelimit())
+#endif
+ printk(KERN_DEBUG "%s: beacon TSF higher than "
+ "local TSF - IBSS merge with BSSID %s\n",
+ dev->name, print_mac(mac, mgmt->bssid));
+ ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss);
+ ieee80211_ibss_add_sta(dev, NULL,
+ mgmt->bssid, mgmt->sa);
+ }
+ }
+
ieee80211_rx_bss_put(dev, bss);
}
static void ieee80211_rx_mgmt_action(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
- size_t len)
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
if (len < IEEE80211_MIN_ACTION_SIZE)
return;
break;
ieee80211_sta_process_addba_request(dev, mgmt, len);
break;
+ case WLAN_ACTION_ADDBA_RESP:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.addba_resp)))
+ break;
+ ieee80211_sta_process_addba_resp(dev, mgmt, len);
+ break;
case WLAN_ACTION_DELBA:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.delba)))
break;
}
break;
+ case PLINK_CATEGORY:
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_rx_plink_frame(dev, mgmt, len, rx_status);
+ break;
+ case MESH_PATH_SEL_CATEGORY:
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_rx_path_sel_frame(dev, mgmt, len);
+ break;
default:
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: Rx unknown action frame - "
+ "category=%d\n", dev->name, mgmt->u.action.category);
break;
}
}
case IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
+ case IEEE80211_STYPE_ACTION:
memcpy(skb->cb, rx_status, sizeof(*rx_status));
case IEEE80211_STYPE_AUTH:
case IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_STYPE_REASSOC_RESP:
case IEEE80211_STYPE_DEAUTH:
case IEEE80211_STYPE_DISASSOC:
- case IEEE80211_STYPE_ACTION:
skb_queue_tail(&ifsta->skb_queue, skb);
queue_work(local->hw.workqueue, &ifsta->work);
return;
ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
break;
case IEEE80211_STYPE_ACTION:
- ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len);
+ ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status);
break;
}
}
-ieee80211_txrx_result
+ieee80211_rx_result
ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status)
{
u16 fc;
if (skb->len < 2)
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
mgmt = (struct ieee80211_mgmt *) skb->data;
fc = le16_to_cpu(mgmt->frame_control);
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
if (skb->len < 24)
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
ieee80211_rx_mgmt_probe_resp(dev, mgmt,
skb->len, rx_status);
dev_kfree_skb(skb);
- return TXRX_QUEUED;
+ return RX_QUEUED;
} else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
rx_status);
dev_kfree_skb(skb);
- return TXRX_QUEUED;
+ return RX_QUEUED;
}
}
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int active = 0;
struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ rcu_read_lock();
- read_lock_bh(&local->sta_lock);
- list_for_each_entry(sta, &local->sta_list, list) {
- if (sta->dev == dev &&
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (sta->sdata == sdata &&
time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
jiffies)) {
active++;
break;
}
}
- read_unlock_bh(&local->sta_lock);
+
+ rcu_read_unlock();
return active;
}
-static void ieee80211_sta_expire(struct net_device *dev)
+static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta, *tmp;
LIST_HEAD(tmp_list);
DECLARE_MAC_BUF(mac);
+ unsigned long flags;
- write_lock_bh(&local->sta_lock);
+ spin_lock_irqsave(&local->sta_lock, flags);
list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
- if (time_after(jiffies, sta->last_rx +
- IEEE80211_IBSS_INACTIVITY_LIMIT)) {
+ if (time_after(jiffies, sta->last_rx + exp_time)) {
printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
dev->name, print_mac(mac, sta->addr));
- __sta_info_get(sta);
- sta_info_remove(sta);
- list_add(&sta->list, &tmp_list);
+ sta_info_unlink(&sta);
+ if (sta)
+ list_add(&sta->list, &tmp_list);
}
- write_unlock_bh(&local->sta_lock);
+ spin_unlock_irqrestore(&local->sta_lock, flags);
- list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
- sta_info_free(sta);
- sta_info_put(sta);
- }
+ synchronize_rcu();
+
+ rtnl_lock();
+ list_for_each_entry_safe(sta, tmp, &tmp_list, list)
+ sta_info_destroy(sta);
+ rtnl_unlock();
}
{
mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
- ieee80211_sta_expire(dev);
+ ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT);
if (ieee80211_sta_active_ibss(dev))
return;
}
+#ifdef CONFIG_MAC80211_MESH
+static void ieee80211_mesh_housekeeping(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ bool free_plinks;
+
+ ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
+ mesh_path_expire(dev);
+
+ free_plinks = mesh_plink_availables(sdata);
+ if (free_plinks != sdata->u.sta.accepting_plinks)
+ ieee80211_if_config_beacon(dev);
+
+ mod_timer(&ifsta->timer, jiffies +
+ IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
+}
+
+
+void ieee80211_start_mesh(struct net_device *dev)
+{
+ struct ieee80211_if_sta *ifsta;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ifsta = &sdata->u.sta;
+ ifsta->state = IEEE80211_MESH_UP;
+ ieee80211_sta_timer((unsigned long)sdata);
+}
+#endif
+
+
void ieee80211_sta_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
queue_work(local->hw.workqueue, &ifsta->work);
}
-
void ieee80211_sta_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
return;
if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
+ sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) {
printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
"(type=%d)\n", dev->name, sdata->vif.type);
return;
while ((skb = skb_dequeue(&ifsta->skb_queue)))
ieee80211_sta_rx_queued_mgmt(dev, skb);
+#ifdef CONFIG_MAC80211_MESH
+ if (ifsta->preq_queue_len &&
+ time_after(jiffies,
+ ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval)))
+ mesh_path_start_discovery(dev);
+#endif
+
if (ifsta->state != IEEE80211_AUTHENTICATE &&
ifsta->state != IEEE80211_ASSOCIATE &&
test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
case IEEE80211_IBSS_JOINED:
ieee80211_sta_merge_ibss(dev, ifsta);
break;
+#ifdef CONFIG_MAC80211_MESH
+ case IEEE80211_MESH_UP:
+ ieee80211_mesh_housekeeping(dev, ifsta);
+ break;
+#endif
default:
printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
ifsta->state);
}
spin_lock_bh(&local->sta_bss_lock);
- freq = local->oper_channel->freq;
+ freq = local->oper_channel->center_freq;
list_for_each_entry(bss, &local->sta_bss_list, list) {
if (!(bss->capability & WLAN_CAPABILITY_ESS))
continue;
spin_unlock_bh(&local->sta_bss_lock);
if (selected) {
- ieee80211_set_channel(local, -1, selected->freq);
+ ieee80211_set_freq(local, selected->freq);
if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
ieee80211_sta_set_ssid(dev, selected->ssid,
selected->ssid_len);
return -1;
}
-static int ieee80211_sta_join_ibss(struct net_device *dev,
- struct ieee80211_if_sta *ifsta,
- struct ieee80211_sta_bss *bss)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- int res, rates, i, j;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- struct ieee80211_tx_control control;
- struct ieee80211_hw_mode *mode;
- struct rate_selection ratesel;
- u8 *pos;
- struct ieee80211_sub_if_data *sdata;
-
- /* Remove possible STA entries from other IBSS networks. */
- sta_info_flush(local, NULL);
-
- if (local->ops->reset_tsf) {
- /* Reset own TSF to allow time synchronization work. */
- local->ops->reset_tsf(local_to_hw(local));
- }
- memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
- res = ieee80211_if_config(dev);
- if (res)
- return res;
-
- local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sdata->drop_unencrypted = bss->capability &
- WLAN_CAPABILITY_PRIVACY ? 1 : 0;
-
- res = ieee80211_set_channel(local, -1, bss->freq);
-
- if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) {
- printk(KERN_DEBUG "%s: IBSS not allowed on channel %d "
- "(%d MHz)\n", dev->name, local->hw.conf.channel,
- local->hw.conf.freq);
- return -1;
- }
-
- /* Set beacon template based on scan results */
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
- do {
- if (!skb)
- break;
-
- skb_reserve(skb, local->hw.extra_tx_headroom);
-
- mgmt = (struct ieee80211_mgmt *)
- skb_put(skb, 24 + sizeof(mgmt->u.beacon));
- memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
- mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
- IEEE80211_STYPE_BEACON);
- memset(mgmt->da, 0xff, ETH_ALEN);
- memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- mgmt->u.beacon.beacon_int =
- cpu_to_le16(local->hw.conf.beacon_int);
- mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
-
- pos = skb_put(skb, 2 + ifsta->ssid_len);
- *pos++ = WLAN_EID_SSID;
- *pos++ = ifsta->ssid_len;
- memcpy(pos, ifsta->ssid, ifsta->ssid_len);
-
- rates = bss->supp_rates_len;
- if (rates > 8)
- rates = 8;
- pos = skb_put(skb, 2 + rates);
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos++ = rates;
- memcpy(pos, bss->supp_rates, rates);
-
- pos = skb_put(skb, 2 + 1);
- *pos++ = WLAN_EID_DS_PARAMS;
- *pos++ = 1;
- *pos++ = bss->channel;
-
- pos = skb_put(skb, 2 + 2);
- *pos++ = WLAN_EID_IBSS_PARAMS;
- *pos++ = 2;
- /* FIX: set ATIM window based on scan results */
- *pos++ = 0;
- *pos++ = 0;
-
- if (bss->supp_rates_len > 8) {
- rates = bss->supp_rates_len - 8;
- pos = skb_put(skb, 2 + rates);
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = rates;
- memcpy(pos, &bss->supp_rates[8], rates);
- }
-
- memset(&control, 0, sizeof(control));
- rate_control_get_rate(dev, local->oper_hw_mode, skb, &ratesel);
- if (!ratesel.rate) {
- printk(KERN_DEBUG "%s: Failed to determine TX rate "
- "for IBSS beacon\n", dev->name);
- break;
- }
- control.vif = &sdata->vif;
- control.tx_rate =
- (sdata->bss_conf.use_short_preamble &&
- (ratesel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
- ratesel.rate->val2 : ratesel.rate->val;
- control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control.power_level = local->hw.conf.power_level;
- control.flags |= IEEE80211_TXCTL_NO_ACK;
- control.retry_limit = 1;
-
- ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
- if (ifsta->probe_resp) {
- mgmt = (struct ieee80211_mgmt *)
- ifsta->probe_resp->data;
- mgmt->frame_control =
- IEEE80211_FC(IEEE80211_FTYPE_MGMT,
- IEEE80211_STYPE_PROBE_RESP);
- } else {
- printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
- "template for IBSS\n", dev->name);
- }
-
- if (local->ops->beacon_update &&
- local->ops->beacon_update(local_to_hw(local),
- skb, &control) == 0) {
- printk(KERN_DEBUG "%s: Configured IBSS beacon "
- "template based on scan results\n", dev->name);
- skb = NULL;
- }
-
- rates = 0;
- mode = local->oper_hw_mode;
- for (i = 0; i < bss->supp_rates_len; i++) {
- int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
- for (j = 0; j < mode->num_rates; j++)
- if (mode->rates[j].rate == bitrate)
- rates |= BIT(j);
- }
- ifsta->supp_rates_bits = rates;
- } while (0);
-
- if (skb) {
- printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
- "template\n", dev->name);
- dev_kfree_skb(skb);
- }
-
- ifsta->state = IEEE80211_IBSS_JOINED;
- mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
-
- ieee80211_rx_bss_put(dev, bss);
-
- return res;
-}
-
static int ieee80211_sta_create_ibss(struct net_device *dev,
struct ieee80211_if_sta *ifsta)
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_hw_mode *mode;
+ struct ieee80211_supported_band *sband;
u8 bssid[ETH_ALEN], *pos;
int i;
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n",
dev->name, print_mac(mac, bssid));
- bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel,
+ bss = ieee80211_rx_bss_add(dev, bssid,
+ local->hw.conf.channel->center_freq,
sdata->u.sta.ssid, sdata->u.sta.ssid_len);
if (!bss)
return -ENOMEM;
- mode = local->oper_hw_mode;
+ bss->band = local->hw.conf.channel->band;
+ sband = local->hw.wiphy->bands[bss->band];
if (local->hw.conf.beacon_int == 0)
- local->hw.conf.beacon_int = 100;
+ local->hw.conf.beacon_int = 10000;
bss->beacon_int = local->hw.conf.beacon_int;
- bss->hw_mode = local->hw.conf.phymode;
- bss->freq = local->hw.conf.freq;
bss->last_update = jiffies;
bss->capability = WLAN_CAPABILITY_IBSS;
if (sdata->default_key) {
bss->capability |= WLAN_CAPABILITY_PRIVACY;
} else
sdata->drop_unencrypted = 0;
- bss->supp_rates_len = mode->num_rates;
+ bss->supp_rates_len = sband->n_bitrates;
pos = bss->supp_rates;
- for (i = 0; i < mode->num_rates; i++) {
- int rate = mode->rates[i].rate;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ int rate = sband->bitrates[i].bitrate;
*pos++ = (u8) (rate / 5);
}
"%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid));
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
- (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel,
+ (bss = ieee80211_rx_bss_get(dev, bssid,
+ local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len))) {
printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
" based on configured SSID\n",
if (time_after(jiffies, ifsta->ibss_join_req +
IEEE80211_IBSS_JOIN_TIMEOUT)) {
if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&
- local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)
+ (!(local->oper_channel->flags &
+ IEEE80211_CHAN_NO_IBSS)))
return ieee80211_sta_create_ibss(dev, ifsta);
if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) {
- printk(KERN_DEBUG "%s: IBSS not allowed on the"
- " configured channel %d (%d MHz)\n",
- dev->name, local->hw.conf.channel,
- local->hw.conf.freq);
+ printk(KERN_DEBUG "%s: IBSS not allowed on"
+ " %d MHz\n", dev->name,
+ local->hw.conf.channel->center_freq);
}
/* No IBSS found - decrease scan interval and continue
int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int i;
memset(&qparam, 0, sizeof(qparam));
- /* TODO: are these ok defaults for all hw_modes? */
+
qparam.aifs = 2;
- qparam.cw_min =
- local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15;
+
+ if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+ !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
+ qparam.cw_min = 31;
+ else
+ qparam.cw_min = 15;
+
qparam.cw_max = 1023;
- qparam.burst_time = 0;
+ qparam.txop = 0;
+
for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
- {
local->ops->conf_tx(local_to_hw(local),
i + IEEE80211_TX_QUEUE_DATA0,
&qparam);
- }
+
/* IBSS uses different parameters for Beacon sending */
qparam.cw_min++;
qparam.cw_min *= 2;
IEEE80211_TX_QUEUE_BEACON, &qparam);
}
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ifsta = &sdata->u.sta;
if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
}
+static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+ ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_sta_timer((unsigned long)sdata);
+}
+
void ieee80211_scan_completed(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
if (local->sta_hw_scanning) {
local->sta_hw_scanning = 0;
+ /* Restart STA timer for HW scan case */
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list)
+ ieee80211_restart_sta_timer(sdata);
+ rcu_read_unlock();
+
goto done;
}
if (sdata->dev == local->mdev)
continue;
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
- if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
- ieee80211_send_nullfunc(local, sdata, 0);
- ieee80211_sta_timer((unsigned long)sdata);
- }
+ /* Tell AP we're back */
+ if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
+ sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
+ ieee80211_send_nullfunc(local, sdata, 0);
+
+ ieee80211_restart_sta_timer(sdata);
netif_wake_queue(sdata->dev);
}
container_of(work, struct ieee80211_local, scan_work.work);
struct net_device *dev = local->scan_dev;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_hw_mode *mode;
+ struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
int skip;
unsigned long next_delay = 0;
switch (local->scan_state) {
case SCAN_SET_CHANNEL:
- mode = local->scan_hw_mode;
- if (local->scan_hw_mode->list.next == &local->modes_list &&
- local->scan_channel_idx >= mode->num_channels) {
+ /*
+ * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
+ * after we successfully scanned the last channel of the last
+ * band (and the last band is supported by the hw)
+ */
+ if (local->scan_band < IEEE80211_NUM_BANDS)
+ sband = local->hw.wiphy->bands[local->scan_band];
+ else
+ sband = NULL;
+
+ /*
+ * If we are at an unsupported band and have more bands
+ * left to scan, advance to the next supported one.
+ */
+ while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
+ local->scan_band++;
+ sband = local->hw.wiphy->bands[local->scan_band];
+ local->scan_channel_idx = 0;
+ }
+
+ /* if no more bands/channels left, complete scan */
+ if (!sband || local->scan_channel_idx >= sband->n_channels) {
ieee80211_scan_completed(local_to_hw(local));
return;
}
- skip = !(local->enabled_modes & (1 << mode->mode));
- chan = &mode->channels[local->scan_channel_idx];
- if (!(chan->flag & IEEE80211_CHAN_W_SCAN) ||
+ skip = 0;
+ chan = &sband->channels[local->scan_channel_idx];
+
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
(sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
- !(chan->flag & IEEE80211_CHAN_W_IBSS)) ||
- (local->hw_modes & local->enabled_modes &
- (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+ chan->flags & IEEE80211_CHAN_NO_IBSS))
skip = 1;
if (!skip) {
-#if 0
- printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n",
- dev->name, chan->chan, chan->freq);
-#endif
-
local->scan_channel = chan;
if (ieee80211_hw_config(local)) {
- printk(KERN_DEBUG "%s: failed to set channel "
- "%d (%d MHz) for scan\n", dev->name,
- chan->chan, chan->freq);
+ printk(KERN_DEBUG "%s: failed to set freq to "
+ "%d MHz for scan\n", dev->name,
+ chan->center_freq);
skip = 1;
}
}
+ /* advance state machine to next channel/band */
local->scan_channel_idx++;
- if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) {
- if (local->scan_hw_mode->list.next != &local->modes_list) {
- local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next,
- struct ieee80211_hw_mode,
- list);
- local->scan_channel_idx = 0;
- }
+ if (local->scan_channel_idx >= sband->n_channels) {
+ /*
+ * scan_band may end up == IEEE80211_NUM_BANDS, but
+ * we'll catch that case above and complete the scan
+ * if that is the case.
+ */
+ local->scan_band++;
+ local->scan_channel_idx = 0;
}
if (skip)
local->scan_state = SCAN_SEND_PROBE;
break;
case SCAN_SEND_PROBE:
- if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) {
- ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
- local->scan_ssid_len);
- next_delay = IEEE80211_CHANNEL_TIME;
- } else
- next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+ next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
local->scan_state = SCAN_SET_CHANNEL;
+
+ if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ break;
+ ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
+ local->scan_ssid_len);
+ next_delay = IEEE80211_CHANNEL_TIME;
break;
}
} else
local->scan_ssid_len = 0;
local->scan_state = SCAN_SET_CHANNEL;
- local->scan_hw_mode = list_entry(local->modes_list.next,
- struct ieee80211_hw_mode,
- list);
local->scan_channel_idx = 0;
+ local->scan_band = IEEE80211_BAND_2GHZ;
local->scan_dev = dev;
netif_tx_lock_bh(local->mdev);
bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
return current_ev;
- if (!(local->enabled_modes & (1 << bss->hw_mode)))
- return current_ev;
-
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWESSID;
- iwe.u.data.length = bss->ssid_len;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
- bss->ssid);
+ if (bss_mesh_cfg(bss)) {
+ iwe.u.data.length = bss_mesh_id_len(bss);
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss_mesh_id(bss));
+ } else {
+ iwe.u.data.length = bss->ssid_len;
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss->ssid);
+ }
- if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+ if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
+ || bss_mesh_cfg(bss)) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWMODE;
- if (bss->capability & WLAN_CAPABILITY_ESS)
+ if (bss_mesh_cfg(bss))
+ iwe.u.mode = IW_MODE_MESH;
+ else if (bss->capability & WLAN_CAPABILITY_ESS)
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = bss->channel;
- iwe.u.freq.e = 0;
+ iwe.u.freq.m = bss->freq;
+ iwe.u.freq.e = 6;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
- iwe.u.freq.m = bss->freq * 100000;
- iwe.u.freq.e = 1;
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
+ iwe.u.freq.e = 0;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
}
}
+ if (bss_mesh_cfg(bss)) {
+ char *buf;
+ u8 *cfg = bss_mesh_cfg(bss);
+ buf = kmalloc(50, GFP_ATOMIC);
+ if (buf) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "Mesh network (version %d)", cfg[0]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ sprintf(buf, "Path Selection Protocol ID: "
+ "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
+ cfg[4]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ sprintf(buf, "Path Selection Metric ID: "
+ "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
+ cfg[8]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ sprintf(buf, "Congestion Control Mode ID: "
+ "0x%02X%02X%02X%02X", cfg[9], cfg[10],
+ cfg[11], cfg[12]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ sprintf(buf, "Channel Precedence: "
+ "0x%02X%02X%02X%02X", cfg[13], cfg[14],
+ cfg[15], cfg[16]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ kfree(buf);
+ }
+ }
+
return current_ev;
}
printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name);
- sta = sta_info_add(local, dev, addr, GFP_ATOMIC);
+ sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
if (!sta)
return NULL;
- sta->supp_rates = sdata->u.sta.supp_rates_bits;
+ sta->flags |= WLAN_STA_AUTHORIZED;
+
+ sta->supp_rates[local->hw.conf.channel->band] =
+ sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
rate_control_rate_init(sta, local);
- return sta; /* caller will call sta_info_put() */
+ if (sta_info_insert(sta)) {
+ sta_info_destroy(sta);
+ return NULL;
+ }
+
+ return sta;
}
#include <linux/etherdevice.h>
#include <linux/list.h>
#include <linux/rcupdate.h>
+#include <linux/rtnetlink.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "debugfs_key.h"
#include "aes_ccm.h"
-/*
- * Key handling basics
+/**
+ * DOC: Key handling basics
*
* Key handling in mac80211 is done based on per-interface (sub_if_data)
* keys and per-station keys. Since each station belongs to an interface,
*
* All operations here are called under RTNL so no extra locking is
* required.
+ *
+ * NOTE: This code requires that sta info *destruction* is done under
+ * RTNL, otherwise it can try to access already freed STA structs
+ * when a STA key is being freed.
*/
static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
key->conf.keyidx, print_mac(mac, addr), ret);
}
+static void ieee80211_key_mark_hw_accel_off(struct ieee80211_key *key)
+{
+ if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
+ key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+ key->flags |= KEY_FLAG_REMOVE_FROM_HARDWARE;
+ }
+}
+
static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
{
const u8 *addr;
int ret;
DECLARE_MAC_BUF(mac);
- if (!key->local->ops->set_key)
+ if (!key || !key->local->ops->set_key)
return;
- if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+ !(key->flags & KEY_FLAG_REMOVE_FROM_HARDWARE))
return;
addr = get_mac_for_key(key);
wiphy_name(key->local->hw.wiphy),
key->conf.keyidx, print_mac(mac, addr), ret);
- key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+ key->flags &= ~(KEY_FLAG_UPLOADED_TO_HARDWARE |
+ KEY_FLAG_REMOVE_FROM_HARDWARE);
}
-struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta,
- enum ieee80211_key_alg alg,
+struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
int idx,
size_t key_len,
const u8 *key_data)
key->conf.keyidx = idx;
key->conf.keylen = key_len;
memcpy(key->conf.key, key_data, key_len);
-
- key->local = sdata->local;
- key->sdata = sdata;
- key->sta = sta;
+ INIT_LIST_HEAD(&key->list);
if (alg == ALG_CCMP) {
/*
}
}
- ieee80211_debugfs_key_add(key->local, key);
+ return key;
+}
- /* remove key first */
- if (sta)
- ieee80211_key_free(sta->key);
- else
- ieee80211_key_free(sdata->keys[idx]);
+static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ struct ieee80211_key *key,
+ struct ieee80211_key *new)
+{
+ int idx, defkey;
+
+ if (new)
+ list_add(&new->list, &sdata->key_list);
+
+ if (sta) {
+ rcu_assign_pointer(sta->key, new);
+ } else {
+ WARN_ON(new && key && new->conf.keyidx != key->conf.keyidx);
+
+ if (key)
+ idx = key->conf.keyidx;
+ else
+ idx = new->conf.keyidx;
+
+ defkey = key && sdata->default_key == key;
+
+ if (defkey && !new)
+ ieee80211_set_default_key(sdata, -1);
+
+ rcu_assign_pointer(sdata->keys[idx], new);
+ if (defkey && new)
+ ieee80211_set_default_key(sdata, new->conf.keyidx);
+ }
+
+ if (key) {
+ ieee80211_key_mark_hw_accel_off(key);
+ /*
+ * We'll use an empty list to indicate that the key
+ * has already been removed.
+ */
+ list_del_init(&key->list);
+ }
+}
+
+void ieee80211_key_link(struct ieee80211_key *key,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta)
+{
+ struct ieee80211_key *old_key;
+ int idx;
+
+ ASSERT_RTNL();
+ might_sleep();
+
+ BUG_ON(!sdata);
+ BUG_ON(!key);
+
+ idx = key->conf.keyidx;
+ key->local = sdata->local;
+ key->sdata = sdata;
+ key->sta = sta;
+
+ ieee80211_debugfs_key_add(key->local, key);
if (sta) {
ieee80211_debugfs_key_sta_link(key, sta);
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
struct sta_info *ap;
+ rcu_read_lock();
+
/* same here, the AP could be using QoS */
ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
if (ap) {
if (ap->flags & WLAN_STA_WME)
key->conf.flags |=
IEEE80211_KEY_FLAG_WMM_STA;
- sta_info_put(ap);
}
+
+ rcu_read_unlock();
}
}
- /* enable hwaccel if appropriate */
- if (netif_running(key->sdata->dev))
- ieee80211_key_enable_hw_accel(key);
-
if (sta)
- rcu_assign_pointer(sta->key, key);
+ old_key = sta->key;
else
- rcu_assign_pointer(sdata->keys[idx], key);
+ old_key = sdata->keys[idx];
- list_add(&key->list, &sdata->key_list);
+ __ieee80211_key_replace(sdata, sta, old_key, key);
- return key;
+ if (old_key) {
+ synchronize_rcu();
+ ieee80211_key_free(old_key);
+ }
+
+ if (netif_running(sdata->dev))
+ ieee80211_key_enable_hw_accel(key);
}
void ieee80211_key_free(struct ieee80211_key *key)
{
+ ASSERT_RTNL();
+ might_sleep();
+
if (!key)
return;
- if (key->sta) {
- rcu_assign_pointer(key->sta->key, NULL);
- } else {
- if (key->sdata->default_key == key)
- ieee80211_set_default_key(key->sdata, -1);
- if (key->conf.keyidx >= 0 &&
- key->conf.keyidx < NUM_DEFAULT_KEYS)
- rcu_assign_pointer(key->sdata->keys[key->conf.keyidx],
- NULL);
- else
- WARN_ON(1);
- }
+ if (key->sdata) {
+ /*
+ * Replace key with nothingness.
+ *
+ * Because other code may have key reference (RCU protected)
+ * right now, we then wait for a grace period before freeing
+ * it.
+ * An empty list indicates it was never added to the key list
+ * or has been removed already. It may, however, still be in
+ * hardware for acceleration.
+ */
+ if (!list_empty(&key->list))
+ __ieee80211_key_replace(key->sdata, key->sta,
+ key, NULL);
- /* wait for all key users to complete */
- synchronize_rcu();
+ /*
+ * Do NOT remove this without looking at sta_info_destroy()
+ */
+ synchronize_rcu();
- /* remove from hwaccel if appropriate */
- ieee80211_key_disable_hw_accel(key);
+ /*
+ * Remove from hwaccel if appropriate, this will
+ * only happen when the key is actually unlinked,
+ * it will already be done when the key was replaced.
+ */
+ ieee80211_key_disable_hw_accel(key);
+ }
if (key->conf.alg == ALG_CCMP)
ieee80211_aes_key_free(key->u.ccmp.tfm);
ieee80211_debugfs_key_remove(key);
- list_del(&key->list);
-
kfree(key);
}
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_key *key, *tmp;
+ LIST_HEAD(tmp_list);
+
+ ASSERT_RTNL();
+ might_sleep();
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
ieee80211_key_free(key);
{
struct ieee80211_key *key;
- WARN_ON(!netif_running(sdata->dev));
- if (!netif_running(sdata->dev))
+ ASSERT_RTNL();
+ might_sleep();
+
+ if (WARN_ON(!netif_running(sdata->dev)))
return;
list_for_each_entry(key, &sdata->key_list, list)
{
struct ieee80211_key *key;
+ ASSERT_RTNL();
+ might_sleep();
+
list_for_each_entry(key, &sdata->key_list, list)
ieee80211_key_disable_hw_accel(key);
}
--- /dev/null
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Authors: Luis Carlos Cobo <luisca@cozybit.com>
+ * Javier Cardona <javier@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ieee80211_i.h"
+#include "mesh.h"
+
+#define PP_OFFSET 1 /* Path Selection Protocol */
+#define PM_OFFSET 5 /* Path Selection Metric */
+#define CC_OFFSET 9 /* Congestion Control Mode */
+#define CAPAB_OFFSET 17
+#define ACCEPT_PLINKS 0x80
+
+int mesh_allocated;
+static struct kmem_cache *rm_cache;
+
+void ieee80211s_init(void)
+{
+ mesh_pathtbl_init();
+ mesh_allocated = 1;
+ rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
+ 0, 0, NULL);
+}
+
+void ieee80211s_stop(void)
+{
+ mesh_pathtbl_unregister();
+ kmem_cache_destroy(rm_cache);
+}
+
+/**
+ * mesh_matches_local - check if the config of a mesh point matches ours
+ *
+ * @ie: information elements of a management frame from the mesh peer
+ * @dev: local mesh interface
+ *
+ * This function checks if the mesh configuration of a mesh point matches the
+ * local mesh configuration, i.e. if both nodes belong to the same mesh network.
+ */
+bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *sta = &sdata->u.sta;
+
+ /*
+ * As support for each feature is added, check for matching
+ * - On mesh config capabilities
+ * - Power Save Support En
+ * - Sync support enabled
+ * - Sync support active
+ * - Sync support required from peer
+ * - MDA enabled
+ * - Power management control on fc
+ */
+ if (sta->mesh_id_len == ie->mesh_id_len &&
+ memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+ memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
+ memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
+ memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
+ return true;
+
+ return false;
+}
+
+/**
+ * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links
+ *
+ * @ie: information elements of a management frame from the mesh peer
+ * @dev: local mesh interface
+ */
+bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
+ struct net_device *dev)
+{
+ return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0;
+}
+
+/**
+ * mesh_accept_plinks_update: update accepting_plink in local mesh beacons
+ *
+ * @sdata: mesh interface in which mesh beacons are going to be updated
+ */
+void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
+{
+ bool free_plinks;
+
+ /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
+ * the mesh interface might be able to establish plinks with peers that
+ * are already on the table but are not on PLINK_ESTAB state. However,
+ * in general the mesh interface is not accepting peer link requests
+ * from new peers, and that must be reflected in the beacon
+ */
+ free_plinks = mesh_plink_availables(sdata);
+
+ if (free_plinks != sdata->u.sta.accepting_plinks)
+ ieee80211_sta_timer((unsigned long) sdata);
+}
+
+void mesh_ids_set_default(struct ieee80211_if_sta *sta)
+{
+ u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff};
+
+ memcpy(sta->mesh_pp_id, def_id, 4);
+ memcpy(sta->mesh_pm_id, def_id, 4);
+ memcpy(sta->mesh_cc_id, def_id, 4);
+}
+
+int mesh_rmc_init(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int i;
+
+ sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
+ if (!sdata->u.sta.rmc)
+ return -ENOMEM;
+ sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1;
+ for (i = 0; i < RMC_BUCKETS; i++)
+ INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list);
+ return 0;
+}
+
+void mesh_rmc_free(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_rmc *rmc = sdata->u.sta.rmc;
+ struct rmc_entry *p, *n;
+ int i;
+
+ if (!sdata->u.sta.rmc)
+ return;
+
+ for (i = 0; i < RMC_BUCKETS; i++)
+ list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) {
+ list_del(&p->list);
+ kmem_cache_free(rm_cache, p);
+ }
+
+ kfree(rmc);
+ sdata->u.sta.rmc = NULL;
+}
+
+/**
+ * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
+ *
+ * @sa: source address
+ * @mesh_hdr: mesh_header
+ *
+ * Returns: 0 if the frame is not in the cache, nonzero otherwise.
+ *
+ * Checks using the source address and the mesh sequence number if we have
+ * received this frame lately. If the frame is not in the cache, it is added to
+ * it.
+ */
+int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
+ struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_rmc *rmc = sdata->u.sta.rmc;
+ u32 seqnum = 0;
+ int entries = 0;
+ u8 idx;
+ struct rmc_entry *p, *n;
+
+ /* Don't care about endianness since only match matters */
+ memcpy(&seqnum, mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
+ idx = mesh_hdr->seqnum[0] & rmc->idx_mask;
+ list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) {
+ ++entries;
+ if (time_after(jiffies, p->exp_time) ||
+ (entries == RMC_QUEUE_MAX_LEN)) {
+ list_del(&p->list);
+ kmem_cache_free(rm_cache, p);
+ --entries;
+ } else if ((seqnum == p->seqnum)
+ && (memcmp(sa, p->sa, ETH_ALEN) == 0))
+ return -1;
+ }
+
+ p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
+ if (!p) {
+ printk(KERN_DEBUG "o11s: could not allocate RMC entry\n");
+ return 0;
+ }
+ p->seqnum = seqnum;
+ p->exp_time = jiffies + RMC_TIMEOUT;
+ memcpy(p->sa, sa, ETH_ALEN);
+ list_add(&p->list, &rmc->bucket[idx].list);
+ return 0;
+}
+
+void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_supported_band *sband;
+ u8 *pos;
+ int len, i, rate;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ len = sband->n_bitrates;
+ if (len > 8)
+ len = 8;
+ pos = skb_put(skb, len + 2);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = len;
+ for (i = 0; i < len; i++) {
+ rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
+
+ if (sband->n_bitrates > len) {
+ pos = skb_put(skb, sband->n_bitrates - len + 2);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = sband->n_bitrates - len;
+ for (i = len; i < sband->n_bitrates; i++) {
+ rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
+ }
+
+ pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len);
+ *pos++ = WLAN_EID_MESH_ID;
+ *pos++ = sdata->u.sta.mesh_id_len;
+ if (sdata->u.sta.mesh_id_len)
+ memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len);
+
+ pos = skb_put(skb, 21);
+ *pos++ = WLAN_EID_MESH_CONFIG;
+ *pos++ = MESH_CFG_LEN;
+ /* Version */
+ *pos++ = 1;
+
+ /* Active path selection protocol ID */
+ memcpy(pos, sdata->u.sta.mesh_pp_id, 4);
+ pos += 4;
+
+ /* Active path selection metric ID */
+ memcpy(pos, sdata->u.sta.mesh_pm_id, 4);
+ pos += 4;
+
+ /* Congestion control mode identifier */
+ memcpy(pos, sdata->u.sta.mesh_cc_id, 4);
+ pos += 4;
+
+ /* Channel precedence:
+ * Not running simple channel unification protocol
+ */
+ memset(pos, 0x00, 4);
+ pos += 4;
+
+ /* Mesh capability */
+ sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata);
+ *pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00;
+ *pos++ = 0x00;
+
+ return;
+}
+
+u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl)
+{
+ /* Use last four bytes of hw addr and interface index as hash index */
+ return jhash_2words(*(u32 *)(addr+2), dev->ifindex, tbl->hash_rnd)
+ & tbl->hash_mask;
+}
+
+u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len)
+{
+ if (!mesh_id_len)
+ return 1;
+ else if (mesh_id_len == 1)
+ return (u8) mesh_id[0];
+ else
+ return (u8) (mesh_id[0] + 2 * mesh_id[1]);
+}
+
+struct mesh_table *mesh_table_alloc(int size_order)
+{
+ int i;
+ struct mesh_table *newtbl;
+
+ newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
+ if (!newtbl)
+ return NULL;
+
+ newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
+ (1 << size_order), GFP_KERNEL);
+
+ if (!newtbl->hash_buckets) {
+ kfree(newtbl);
+ return NULL;
+ }
+
+ newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
+ (1 << size_order), GFP_KERNEL);
+ if (!newtbl->hashwlock) {
+ kfree(newtbl->hash_buckets);
+ kfree(newtbl);
+ return NULL;
+ }
+
+ newtbl->size_order = size_order;
+ newtbl->hash_mask = (1 << size_order) - 1;
+ atomic_set(&newtbl->entries, 0);
+ get_random_bytes(&newtbl->hash_rnd,
+ sizeof(newtbl->hash_rnd));
+ for (i = 0; i <= newtbl->hash_mask; i++)
+ spin_lock_init(&newtbl->hashwlock[i]);
+
+ return newtbl;
+}
+
+void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
+{
+ struct hlist_head *mesh_hash;
+ struct hlist_node *p, *q;
+ int i;
+
+ mesh_hash = tbl->hash_buckets;
+ for (i = 0; i <= tbl->hash_mask; i++) {
+ spin_lock(&tbl->hashwlock[i]);
+ hlist_for_each_safe(p, q, &mesh_hash[i]) {
+ tbl->free_node(p, free_leafs);
+ atomic_dec(&tbl->entries);
+ }
+ spin_unlock(&tbl->hashwlock[i]);
+ }
+ kfree(tbl->hash_buckets);
+ kfree(tbl->hashwlock);
+ kfree(tbl);
+}
+
+static void ieee80211_mesh_path_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_local *local = wdev_priv(&sdata->wdev);
+
+ queue_work(local->hw.workqueue, &ifsta->work);
+}
+
+struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
+{
+ struct mesh_table *newtbl;
+ struct hlist_head *oldhash;
+ struct hlist_node *p;
+ int err = 0;
+ int i;
+
+ if (atomic_read(&tbl->entries)
+ < tbl->mean_chain_len * (tbl->hash_mask + 1)) {
+ err = -EPERM;
+ goto endgrow;
+ }
+
+ newtbl = mesh_table_alloc(tbl->size_order + 1);
+ if (!newtbl) {
+ err = -ENOMEM;
+ goto endgrow;
+ }
+
+ newtbl->free_node = tbl->free_node;
+ newtbl->mean_chain_len = tbl->mean_chain_len;
+ newtbl->copy_node = tbl->copy_node;
+ atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
+
+ oldhash = tbl->hash_buckets;
+ for (i = 0; i <= tbl->hash_mask; i++)
+ hlist_for_each(p, &oldhash[i])
+ tbl->copy_node(p, newtbl);
+
+endgrow:
+ if (err)
+ return NULL;
+ else
+ return newtbl;
+}
+
+/**
+ * ieee80211_new_mesh_header - create a new mesh header
+ * @meshhdr: uninitialized mesh header
+ * @sdata: mesh interface to be used
+ *
+ * Return the header length.
+ */
+int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
+ struct ieee80211_sub_if_data *sdata)
+{
+ meshhdr->flags = 0;
+ meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+
+ meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++;
+ meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1];
+ meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2];
+
+ if (sdata->u.sta.mesh_seqnum[0] == 0) {
+ sdata->u.sta.mesh_seqnum[1]++;
+ if (sdata->u.sta.mesh_seqnum[1] == 0)
+ sdata->u.sta.mesh_seqnum[2]++;
+ }
+
+ return 5;
+}
+
+void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+ ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
+ ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
+ ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
+ ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
+ ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
+ ifsta->mshcfg.auto_open_plinks = true;
+ ifsta->mshcfg.dot11MeshMaxPeerLinks =
+ MESH_MAX_ESTAB_PLINKS;
+ ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
+ MESH_PATH_TIMEOUT;
+ ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
+ MESH_PREQ_MIN_INT;
+ ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
+ MESH_DIAM_TRAVERSAL_TIME;
+ ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
+ MESH_MAX_PREQ_RETRIES;
+ ifsta->mshcfg.path_refresh_time =
+ MESH_PATH_REFRESH_TIME;
+ ifsta->mshcfg.min_discovery_timeout =
+ MESH_MIN_DISCOVERY_TIMEOUT;
+ ifsta->accepting_plinks = true;
+ ifsta->preq_id = 0;
+ ifsta->dsn = 0;
+ atomic_set(&ifsta->mpaths, 0);
+ mesh_rmc_init(sdata->dev);
+ ifsta->last_preq = jiffies;
+ /* Allocate all mesh structures when creating the first mesh interface. */
+ if (!mesh_allocated)
+ ieee80211s_init();
+ mesh_ids_set_default(ifsta);
+ setup_timer(&ifsta->mesh_path_timer,
+ ieee80211_mesh_path_timer,
+ (unsigned long) sdata);
+ INIT_LIST_HEAD(&ifsta->preq_queue.list);
+ spin_lock_init(&ifsta->mesh_preq_queue_lock);
+}
--- /dev/null
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Authors: Luis Carlos Cobo <luisca@cozybit.com>
+ * Javier Cardona <javier@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef IEEE80211S_H
+#define IEEE80211S_H
+
+#include <linux/types.h>
+#include <linux/jhash.h>
+#include "ieee80211_i.h"
+
+
+/* Data structures */
+
+/**
+ * enum mesh_path_flags - mac80211 mesh path flags
+ *
+ *
+ *
+ * @MESH_PATH_ACTIVE: the mesh path is can be used for forwarding
+ * @MESH_PATH_RESOLVED: the discovery process is running for this mesh path
+ * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence
+ * number
+ * @MESH_PATH_FIXED: the mesh path has been manually set and should not be
+ * modified
+ * @MESH_PATH_RESOLVED: the mesh path can has been resolved
+ *
+ * MESH_PATH_RESOLVED and MESH_PATH_DELETE are used by the mesh path timer to
+ * decide when to stop or cancel the mesh path discovery.
+ */
+enum mesh_path_flags {
+ MESH_PATH_ACTIVE = BIT(0),
+ MESH_PATH_RESOLVING = BIT(1),
+ MESH_PATH_DSN_VALID = BIT(2),
+ MESH_PATH_FIXED = BIT(3),
+ MESH_PATH_RESOLVED = BIT(4),
+};
+
+/**
+ * struct mesh_path - mac80211 mesh path structure
+ *
+ * @dst: mesh path destination mac address
+ * @dev: mesh path device
+ * @next_hop: mesh neighbor to which frames for this destination will be
+ * forwarded
+ * @timer: mesh path discovery timer
+ * @frame_queue: pending queue for frames sent to this destination while the
+ * path is unresolved
+ * @dsn: destination sequence number of the destination
+ * @metric: current metric to this destination
+ * @hop_count: hops to destination
+ * @exp_time: in jiffies, when the path will expire or when it expired
+ * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery
+ * retry
+ * @discovery_retries: number of discovery retries
+ * @flags: mesh path flags, as specified on &enum mesh_path_flags
+ * @state_lock: mesh pat state lock
+ *
+ *
+ * The combination of dst and dev is unique in the mesh path table. Since the
+ * next_hop STA is only protected by RCU as well, deleting the STA must also
+ * remove/substitute the mesh_path structure and wait until that is no longer
+ * reachable before destroying the STA completely.
+ */
+struct mesh_path {
+ u8 dst[ETH_ALEN];
+ struct net_device *dev;
+ struct sta_info *next_hop;
+ struct timer_list timer;
+ struct sk_buff_head frame_queue;
+ struct rcu_head rcu;
+ u32 dsn;
+ u32 metric;
+ u8 hop_count;
+ unsigned long exp_time;
+ u32 discovery_timeout;
+ u8 discovery_retries;
+ enum mesh_path_flags flags;
+ spinlock_t state_lock;
+};
+
+/**
+ * struct mesh_table
+ *
+ * @hash_buckets: array of hash buckets of the table
+ * @hashwlock: array of locks to protect write operations, one per bucket
+ * @hash_mask: 2^size_order - 1, used to compute hash idx
+ * @hash_rnd: random value used for hash computations
+ * @entries: number of entries in the table
+ * @free_node: function to free nodes of the table
+ * @copy_node: fuction to copy nodes of the table
+ * @size_order: determines size of the table, there will be 2^size_order hash
+ * buckets
+ * @mean_chain_len: maximum average length for the hash buckets' list, if it is
+ * reached, the table will grow
+ */
+struct mesh_table {
+ /* Number of buckets will be 2^N */
+ struct hlist_head *hash_buckets;
+ spinlock_t *hashwlock; /* One per bucket, for add/del */
+ unsigned int hash_mask; /* (2^size_order) - 1 */
+ __u32 hash_rnd; /* Used for hash generation */
+ atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
+ void (*free_node) (struct hlist_node *p, bool free_leafs);
+ void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
+ int size_order;
+ int mean_chain_len;
+};
+
+/* Recent multicast cache */
+/* RMC_BUCKETS must be a power of 2, maximum 256 */
+#define RMC_BUCKETS 256
+#define RMC_QUEUE_MAX_LEN 4
+#define RMC_TIMEOUT (3 * HZ)
+
+/**
+ * struct rmc_entry - entry in the Recent Multicast Cache
+ *
+ * @seqnum: mesh sequence number of the frame
+ * @exp_time: expiration time of the entry, in jiffies
+ * @sa: source address of the frame
+ *
+ * The Recent Multicast Cache keeps track of the latest multicast frames that
+ * have been received by a mesh interface and discards received multicast frames
+ * that are found in the cache.
+ */
+struct rmc_entry {
+ struct list_head list;
+ u32 seqnum;
+ unsigned long exp_time;
+ u8 sa[ETH_ALEN];
+};
+
+struct mesh_rmc {
+ struct rmc_entry bucket[RMC_BUCKETS];
+ u8 idx_mask;
+};
+
+
+/* Mesh IEs constants */
+#define MESH_CFG_LEN 19
+
+/*
+ * MESH_CFG_COMP_LEN Includes:
+ * - Active path selection protocol ID.
+ * - Active path selection metric ID.
+ * - Congestion control mode identifier.
+ * - Channel precedence.
+ * Does not include mesh capabilities, which may vary across nodes in the same
+ * mesh
+ */
+#define MESH_CFG_CMP_LEN 17
+
+/* Default values, timeouts in ms */
+#define MESH_TTL 5
+#define MESH_MAX_RETR 3
+#define MESH_RET_T 100
+#define MESH_CONF_T 100
+#define MESH_HOLD_T 100
+
+#define MESH_PATH_TIMEOUT 5000
+/* Minimum interval between two consecutive PREQs originated by the same
+ * interface
+ */
+#define MESH_PREQ_MIN_INT 10
+#define MESH_DIAM_TRAVERSAL_TIME 50
+/* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their
+ * expiration
+ */
+#define MESH_PATH_REFRESH_TIME 1000
+#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
+
+#define MESH_MAX_PREQ_RETRIES 4
+#define MESH_PATH_EXPIRE (600 * HZ)
+
+/* Default maximum number of established plinks per interface */
+#define MESH_MAX_ESTAB_PLINKS 32
+
+/* Default maximum number of plinks per interface */
+#define MESH_MAX_PLINKS 256
+
+/* Maximum number of paths per interface */
+#define MESH_MAX_MPATHS 1024
+
+/* Pending ANA approval */
+#define PLINK_CATEGORY 30
+#define MESH_PATH_SEL_CATEGORY 32
+
+/* Mesh Header Flags */
+#define IEEE80211S_FLAGS_AE 0x3
+
+/* Public interfaces */
+/* Various */
+u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len);
+int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
+int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
+ struct ieee80211_sub_if_data *sdata);
+int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
+ struct net_device *dev);
+bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev);
+void mesh_ids_set_default(struct ieee80211_if_sta *sta);
+void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev);
+void mesh_rmc_free(struct net_device *dev);
+int mesh_rmc_init(struct net_device *dev);
+void ieee80211s_init(void);
+void ieee80211s_stop(void);
+void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
+
+/* Mesh paths */
+int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb,
+ struct net_device *dev);
+void mesh_path_start_discovery(struct net_device *dev);
+struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev);
+struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev);
+void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
+void mesh_path_expire(struct net_device *dev);
+void mesh_path_flush(struct net_device *dev);
+void mesh_rx_path_sel_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+ size_t len);
+int mesh_path_add(u8 *dst, struct net_device *dev);
+/* Mesh plinks */
+void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
+ bool add);
+bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
+ struct net_device *dev);
+void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
+void mesh_plink_broken(struct sta_info *sta);
+void mesh_plink_deactivate(struct sta_info *sta);
+int mesh_plink_open(struct sta_info *sta);
+int mesh_plink_close(struct sta_info *sta);
+void mesh_plink_block(struct sta_info *sta);
+void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+ size_t len, struct ieee80211_rx_status *rx_status);
+
+/* Private interfaces */
+/* Mesh tables */
+struct mesh_table *mesh_table_alloc(int size_order);
+void mesh_table_free(struct mesh_table *tbl, bool free_leafs);
+struct mesh_table *mesh_table_grow(struct mesh_table *tbl);
+u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl);
+/* Mesh paths */
+int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra,
+ struct net_device *dev);
+void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
+void mesh_path_flush_pending(struct mesh_path *mpath);
+void mesh_path_tx_pending(struct mesh_path *mpath);
+int mesh_pathtbl_init(void);
+void mesh_pathtbl_unregister(void);
+int mesh_path_del(u8 *addr, struct net_device *dev);
+void mesh_path_timer(unsigned long data);
+void mesh_path_flush_by_nexthop(struct sta_info *sta);
+void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev);
+
+#ifdef CONFIG_MAC80211_MESH
+extern int mesh_allocated;
+
+static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
+{
+ return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks -
+ atomic_read(&sdata->u.sta.mshstats.estab_plinks);
+}
+
+static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata)
+{
+ return (min_t(long, mesh_plink_free_count(sdata),
+ MESH_MAX_PLINKS - sdata->local->num_sta)) > 0;
+}
+
+static inline void mesh_path_activate(struct mesh_path *mpath)
+{
+ mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED;
+}
+
+#define for_each_mesh_entry(x, p, node, i) \
+ for (i = 0; i <= x->hash_mask; i++) \
+ hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
+
+#else
+#define mesh_allocated 0
+#endif
+
+#define MESH_PREQ(skb) (skb->cb + 30)
+
+#endif /* IEEE80211S_H */
--- /dev/null
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author: Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/unaligned.h>
+#include "mesh.h"
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+
+#define TEST_FRAME_LEN 8192
+#define MAX_METRIC 0xffffffff
+#define ARITH_SHIFT 8
+
+/* Number of frames buffered per destination for unresolved destinations */
+#define MESH_FRAME_QUEUE_LEN 10
+#define MAX_PREQ_QUEUE_LEN 64
+
+/* Destination only */
+#define MP_F_DO 0x1
+/* Reply and forward */
+#define MP_F_RF 0x2
+
+static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
+{
+ if (ae)
+ offset += 6;
+ return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset)));
+}
+
+/* HWMP IE processing macros */
+#define AE_F (1<<6)
+#define AE_F_SET(x) (*x & AE_F)
+#define PREQ_IE_FLAGS(x) (*(x))
+#define PREQ_IE_HOPCOUNT(x) (*(x + 1))
+#define PREQ_IE_TTL(x) (*(x + 2))
+#define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0)
+#define PREQ_IE_ORIG_ADDR(x) (x + 7)
+#define PREQ_IE_ORIG_DSN(x) u32_field_get(x, 13, 0);
+#define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x));
+#define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x));
+#define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26))
+#define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27)
+#define PREQ_IE_DST_DSN(x) u32_field_get(x, 33, AE_F_SET(x));
+
+
+#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x)
+#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x)
+#define PREP_IE_TTL(x) PREQ_IE_TTL(x)
+#define PREP_IE_ORIG_ADDR(x) (x + 3)
+#define PREP_IE_ORIG_DSN(x) u32_field_get(x, 9, 0);
+#define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x));
+#define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x));
+#define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21)
+#define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x));
+
+#define PERR_IE_DST_ADDR(x) (x + 2)
+#define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0);
+
+#define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000))
+#define MSEC_TO_TU(x) (x*1000/1024)
+#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0)
+#define DSN_LT(x, y) ((long) (x) - (long) (y) < 0)
+
+#define net_traversal_jiffies(s) \
+ msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
+#define default_lifetime(s) \
+ MSEC_TO_TU(s->u.sta.mshcfg.dot11MeshHWMPactivePathTimeout)
+#define min_preq_int_jiff(s) \
+ (msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPpreqMinInterval))
+#define max_preq_retries(s) (s->u.sta.mshcfg.dot11MeshHWMPmaxPREQretries)
+#define disc_timeout_jiff(s) \
+ msecs_to_jiffies(sdata->u.sta.mshcfg.min_discovery_timeout)
+
+enum mpath_frame_type {
+ MPATH_PREQ = 0,
+ MPATH_PREP,
+ MPATH_PERR
+};
+
+static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
+ u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst,
+ __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime,
+ __le32 metric, __le32 preq_id, struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos;
+ int ie_len;
+
+ if (!skb)
+ return -1;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ /* 25 is the size of the common mgmt part (24) plus the size of the
+ * common action part (1)
+ */
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
+ memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+
+ memcpy(mgmt->da, da, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+ mgmt->u.action.u.mesh_action.action_code = action;
+
+ switch (action) {
+ case MPATH_PREQ:
+ ie_len = 37;
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PREQ;
+ break;
+ case MPATH_PREP:
+ ie_len = 31;
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PREP;
+ break;
+ default:
+ kfree(skb);
+ return -ENOTSUPP;
+ break;
+ }
+ *pos++ = ie_len;
+ *pos++ = flags;
+ *pos++ = hop_count;
+ *pos++ = ttl;
+ if (action == MPATH_PREQ) {
+ memcpy(pos, &preq_id, 4);
+ pos += 4;
+ }
+ memcpy(pos, orig_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &orig_dsn, 4);
+ pos += 4;
+ memcpy(pos, &lifetime, 4);
+ pos += 4;
+ memcpy(pos, &metric, 4);
+ pos += 4;
+ if (action == MPATH_PREQ) {
+ /* destination count */
+ *pos++ = 1;
+ *pos++ = dst_flags;
+ }
+ memcpy(pos, dst, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &dst_dsn, 4);
+
+ ieee80211_sta_tx(dev, skb, 0);
+ return 0;
+}
+
+/**
+ * mesh_send_path error - Sends a PERR mesh management frame
+ *
+ * @dst: broken destination
+ * @dst_dsn: dsn of the broken destination
+ * @ra: node this frame is addressed to
+ */
+int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra,
+ struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos;
+ int ie_len;
+
+ if (!skb)
+ return -1;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ /* 25 is the size of the common mgmt part (24) plus the size of the
+ * common action part (1)
+ */
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
+ memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+
+ memcpy(mgmt->da, ra, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+ mgmt->u.action.u.mesh_action.action_code = MPATH_PERR;
+ ie_len = 12;
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PERR;
+ *pos++ = ie_len;
+ /* mode flags, reserved */
+ *pos++ = 0;
+ /* number of destinations */
+ *pos++ = 1;
+ memcpy(pos, dst, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &dst_dsn, 4);
+
+ ieee80211_sta_tx(dev, skb, 0);
+ return 0;
+}
+
+static u32 airtime_link_metric_get(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_supported_band *sband;
+ /* This should be adjusted for each device */
+ int device_constant = 1 << ARITH_SHIFT;
+ int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT;
+ int s_unit = 1 << ARITH_SHIFT;
+ int rate, err;
+ u32 tx_time, estimated_retx;
+ u64 result;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ if (sta->fail_avg >= 100)
+ return MAX_METRIC;
+ err = (sta->fail_avg << ARITH_SHIFT) / 100;
+
+ /* bitrate is in units of 100 Kbps, while we need rate in units of
+ * 1Mbps. This will be corrected on tx_time computation.
+ */
+ rate = sband->bitrates[sta->txrate_idx].bitrate;
+ tx_time = (device_constant + 10 * test_frame_len / rate);
+ estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
+ result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
+ return (u32)result;
+}
+
+/**
+ * hwmp_route_info_get - Update routing info to originator and transmitter
+ *
+ * @dev: local mesh interface
+ * @mgmt: mesh management frame
+ * @hwmp_ie: hwmp information element (PREP or PREQ)
+ *
+ * This function updates the path routing information to the originator and the
+ * transmitter of a HWMP PREQ or PREP fram.
+ *
+ * Returns: metric to frame originator or 0 if the frame should not be further
+ * processed
+ *
+ * Notes: this function is the only place (besides user-provided info) where
+ * path routing information is updated.
+ */
+static u32 hwmp_route_info_get(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ u8 *hwmp_ie)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct mesh_path *mpath;
+ struct sta_info *sta;
+ bool fresh_info;
+ u8 *orig_addr, *ta;
+ u32 orig_dsn, orig_metric;
+ unsigned long orig_lifetime, exp_time;
+ u32 last_hop_metric, new_metric;
+ bool process = true;
+ u8 action = mgmt->u.action.u.mesh_action.action_code;
+
+ rcu_read_lock();
+ sta = sta_info_get(local, mgmt->sa);
+ if (!sta) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ last_hop_metric = airtime_link_metric_get(local, sta);
+ /* Update and check originator routing info */
+ fresh_info = true;
+
+ switch (action) {
+ case MPATH_PREQ:
+ orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie);
+ orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie);
+ orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie);
+ orig_metric = PREQ_IE_METRIC(hwmp_ie);
+ break;
+ case MPATH_PREP:
+ /* Originator here refers to the MP that was the destination in
+ * the Path Request. The draft refers to that MP as the
+ * destination address, even though usually it is the origin of
+ * the PREP frame. We divert from the nomenclature in the draft
+ * so that we can easily use a single function to gather path
+ * information from both PREQ and PREP frames.
+ */
+ orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie);
+ orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie);
+ orig_lifetime = PREP_IE_LIFETIME(hwmp_ie);
+ orig_metric = PREP_IE_METRIC(hwmp_ie);
+ break;
+ default:
+ rcu_read_unlock();
+ return 0;
+ }
+ new_metric = orig_metric + last_hop_metric;
+ if (new_metric < orig_metric)
+ new_metric = MAX_METRIC;
+ exp_time = TU_TO_EXP_TIME(orig_lifetime);
+
+ if (memcmp(orig_addr, dev->dev_addr, ETH_ALEN) == 0) {
+ /* This MP is the originator, we are not interested in this
+ * frame, except for updating transmitter's path info.
+ */
+ process = false;
+ fresh_info = false;
+ } else {
+ mpath = mesh_path_lookup(orig_addr, dev);
+ if (mpath) {
+ spin_lock_bh(&mpath->state_lock);
+ if (mpath->flags & MESH_PATH_FIXED)
+ fresh_info = false;
+ else if ((mpath->flags & MESH_PATH_ACTIVE) &&
+ (mpath->flags & MESH_PATH_DSN_VALID)) {
+ if (DSN_GT(mpath->dsn, orig_dsn) ||
+ (mpath->dsn == orig_dsn &&
+ action == MPATH_PREQ &&
+ new_metric > mpath->metric)) {
+ process = false;
+ fresh_info = false;
+ }
+ }
+ } else {
+ mesh_path_add(orig_addr, dev);
+ mpath = mesh_path_lookup(orig_addr, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ return 0;
+ }
+ spin_lock_bh(&mpath->state_lock);
+ }
+
+ if (fresh_info) {
+ mesh_path_assign_nexthop(mpath, sta);
+ mpath->flags |= MESH_PATH_DSN_VALID;
+ mpath->metric = new_metric;
+ mpath->dsn = orig_dsn;
+ mpath->exp_time = time_after(mpath->exp_time, exp_time)
+ ? mpath->exp_time : exp_time;
+ mesh_path_activate(mpath);
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_tx_pending(mpath);
+ /* draft says preq_id should be saved to, but there does
+ * not seem to be any use for it, skipping by now
+ */
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+
+ /* Update and check transmitter routing info */
+ ta = mgmt->sa;
+ if (memcmp(orig_addr, ta, ETH_ALEN) == 0)
+ fresh_info = false;
+ else {
+ fresh_info = true;
+
+ mpath = mesh_path_lookup(ta, dev);
+ if (mpath) {
+ spin_lock_bh(&mpath->state_lock);
+ if ((mpath->flags & MESH_PATH_FIXED) ||
+ ((mpath->flags & MESH_PATH_ACTIVE) &&
+ (last_hop_metric > mpath->metric)))
+ fresh_info = false;
+ } else {
+ mesh_path_add(ta, dev);
+ mpath = mesh_path_lookup(ta, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ return 0;
+ }
+ spin_lock_bh(&mpath->state_lock);
+ }
+
+ if (fresh_info) {
+ mesh_path_assign_nexthop(mpath, sta);
+ mpath->flags &= ~MESH_PATH_DSN_VALID;
+ mpath->metric = last_hop_metric;
+ mpath->exp_time = time_after(mpath->exp_time, exp_time)
+ ? mpath->exp_time : exp_time;
+ mesh_path_activate(mpath);
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_tx_pending(mpath);
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+
+ rcu_read_unlock();
+
+ return process ? new_metric : 0;
+}
+
+static void hwmp_preq_frame_process(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ u8 *preq_elem, u32 metric) {
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct mesh_path *mpath;
+ u8 *dst_addr, *orig_addr;
+ u8 dst_flags, ttl;
+ u32 orig_dsn, dst_dsn, lifetime;
+ bool reply = false;
+ bool forward = true;
+
+ /* Update destination DSN, if present */
+ dst_addr = PREQ_IE_DST_ADDR(preq_elem);
+ orig_addr = PREQ_IE_ORIG_ADDR(preq_elem);
+ dst_dsn = PREQ_IE_DST_DSN(preq_elem);
+ orig_dsn = PREQ_IE_ORIG_DSN(preq_elem);
+ dst_flags = PREQ_IE_DST_F(preq_elem);
+
+ if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0) {
+ forward = false;
+ reply = true;
+ metric = 0;
+ if (time_after(jiffies, ifsta->last_dsn_update +
+ net_traversal_jiffies(sdata)) ||
+ time_before(jiffies, ifsta->last_dsn_update)) {
+ dst_dsn = ++ifsta->dsn;
+ ifsta->last_dsn_update = jiffies;
+ }
+ } else {
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst_addr, dev);
+ if (mpath) {
+ if ((!(mpath->flags & MESH_PATH_DSN_VALID)) ||
+ DSN_LT(mpath->dsn, dst_dsn)) {
+ mpath->dsn = dst_dsn;
+ mpath->flags &= MESH_PATH_DSN_VALID;
+ } else if ((!(dst_flags & MP_F_DO)) &&
+ (mpath->flags & MESH_PATH_ACTIVE)) {
+ reply = true;
+ metric = mpath->metric;
+ dst_dsn = mpath->dsn;
+ if (dst_flags & MP_F_RF)
+ dst_flags |= MP_F_DO;
+ else
+ forward = false;
+ }
+ }
+ rcu_read_unlock();
+ }
+
+ if (reply) {
+ lifetime = PREQ_IE_LIFETIME(preq_elem);
+ ttl = ifsta->mshcfg.dot11MeshTTL;
+ if (ttl != 0)
+ mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr,
+ cpu_to_le32(dst_dsn), 0, orig_addr,
+ cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl,
+ cpu_to_le32(lifetime), cpu_to_le32(metric),
+ 0, dev);
+ else
+ ifsta->mshstats.dropped_frames_ttl++;
+ }
+
+ if (forward) {
+ u32 preq_id;
+ u8 hopcount, flags;
+
+ ttl = PREQ_IE_TTL(preq_elem);
+ lifetime = PREQ_IE_LIFETIME(preq_elem);
+ if (ttl <= 1) {
+ ifsta->mshstats.dropped_frames_ttl++;
+ return;
+ }
+ --ttl;
+ flags = PREQ_IE_FLAGS(preq_elem);
+ preq_id = PREQ_IE_PREQ_ID(preq_elem);
+ hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
+ mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
+ cpu_to_le32(orig_dsn), dst_flags, dst_addr,
+ cpu_to_le32(dst_dsn), dev->broadcast,
+ hopcount, ttl, cpu_to_le32(lifetime),
+ cpu_to_le32(metric), cpu_to_le32(preq_id),
+ dev);
+ ifsta->mshstats.fwded_frames++;
+ }
+}
+
+
+static void hwmp_prep_frame_process(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ u8 *prep_elem, u32 metric)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+ u8 *dst_addr, *orig_addr;
+ u8 ttl, hopcount, flags;
+ u8 next_hop[ETH_ALEN];
+ u32 dst_dsn, orig_dsn, lifetime;
+
+ /* Note that we divert from the draft nomenclature and denominate
+ * destination to what the draft refers to as origininator. So in this
+ * function destnation refers to the final destination of the PREP,
+ * which corresponds with the originator of the PREQ which this PREP
+ * replies
+ */
+ dst_addr = PREP_IE_DST_ADDR(prep_elem);
+ if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0)
+ /* destination, no forwarding required */
+ return;
+
+ ttl = PREP_IE_TTL(prep_elem);
+ if (ttl <= 1) {
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ return;
+ }
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst_addr, dev);
+ if (mpath)
+ spin_lock_bh(&mpath->state_lock);
+ else
+ goto fail;
+ if (!(mpath->flags & MESH_PATH_ACTIVE)) {
+ spin_unlock_bh(&mpath->state_lock);
+ goto fail;
+ }
+ memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+ spin_unlock_bh(&mpath->state_lock);
+ --ttl;
+ flags = PREP_IE_FLAGS(prep_elem);
+ lifetime = PREP_IE_LIFETIME(prep_elem);
+ hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1;
+ orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
+ dst_dsn = PREP_IE_DST_DSN(prep_elem);
+ orig_dsn = PREP_IE_ORIG_DSN(prep_elem);
+
+ mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
+ cpu_to_le32(orig_dsn), 0, dst_addr,
+ cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl,
+ cpu_to_le32(lifetime), cpu_to_le32(metric),
+ 0, dev);
+ rcu_read_unlock();
+ sdata->u.sta.mshstats.fwded_frames++;
+ return;
+
+fail:
+ rcu_read_unlock();
+ sdata->u.sta.mshstats.dropped_frames_no_route++;
+ return;
+}
+
+static void hwmp_perr_frame_process(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt, u8 *perr_elem)
+{
+ struct mesh_path *mpath;
+ u8 *ta, *dst_addr;
+ u32 dst_dsn;
+
+ ta = mgmt->sa;
+ dst_addr = PERR_IE_DST_ADDR(perr_elem);
+ dst_dsn = PERR_IE_DST_DSN(perr_elem);
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst_addr, dev);
+ if (mpath) {
+ spin_lock_bh(&mpath->state_lock);
+ if (mpath->flags & MESH_PATH_ACTIVE &&
+ memcmp(ta, mpath->next_hop->addr, ETH_ALEN) == 0 &&
+ (!(mpath->flags & MESH_PATH_DSN_VALID) ||
+ DSN_GT(dst_dsn, mpath->dsn))) {
+ mpath->flags &= ~MESH_PATH_ACTIVE;
+ mpath->dsn = dst_dsn;
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn),
+ dev->broadcast, dev);
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ rcu_read_unlock();
+}
+
+
+
+void mesh_rx_path_sel_frame(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee802_11_elems elems;
+ size_t baselen;
+ u32 last_hop_metric;
+
+ baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
+ ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
+ len - baselen, &elems);
+
+ switch (mgmt->u.action.u.mesh_action.action_code) {
+ case MPATH_PREQ:
+ if (!elems.preq || elems.preq_len != 37)
+ /* Right now we support just 1 destination and no AE */
+ return;
+ last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.preq);
+ if (!last_hop_metric)
+ return;
+ hwmp_preq_frame_process(dev, mgmt, elems.preq, last_hop_metric);
+ break;
+ case MPATH_PREP:
+ if (!elems.prep || elems.prep_len != 31)
+ /* Right now we support no AE */
+ return;
+ last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.prep);
+ if (!last_hop_metric)
+ return;
+ hwmp_prep_frame_process(dev, mgmt, elems.prep, last_hop_metric);
+ break;
+ case MPATH_PERR:
+ if (!elems.perr || elems.perr_len != 12)
+ /* Right now we support only one destination per PERR */
+ return;
+ hwmp_perr_frame_process(dev, mgmt, elems.perr);
+ default:
+ return;
+ }
+
+}
+
+/**
+ * mesh_queue_preq - queue a PREQ to a given destination
+ *
+ * @mpath: mesh path to discover
+ * @flags: special attributes of the PREQ to be sent
+ *
+ * Locking: the function must be called from within a rcu read lock block.
+ *
+ */
+static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
+{
+ struct ieee80211_sub_if_data *sdata =
+ IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct mesh_preq_queue *preq_node;
+
+ preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL);
+ if (!preq_node) {
+ printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n");
+ return;
+ }
+
+ spin_lock(&ifsta->mesh_preq_queue_lock);
+ if (ifsta->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
+ spin_unlock(&ifsta->mesh_preq_queue_lock);
+ kfree(preq_node);
+ if (printk_ratelimit())
+ printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n");
+ return;
+ }
+
+ memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
+ preq_node->flags = flags;
+
+ list_add_tail(&preq_node->list, &ifsta->preq_queue.list);
+ ++ifsta->preq_queue_len;
+ spin_unlock(&ifsta->mesh_preq_queue_lock);
+
+ if (time_after(jiffies, ifsta->last_preq + min_preq_int_jiff(sdata)))
+ queue_work(sdata->local->hw.workqueue, &ifsta->work);
+
+ else if (time_before(jiffies, ifsta->last_preq)) {
+ /* avoid long wait if did not send preqs for a long time
+ * and jiffies wrapped around
+ */
+ ifsta->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
+ queue_work(sdata->local->hw.workqueue, &ifsta->work);
+ } else
+ mod_timer(&ifsta->mesh_path_timer, ifsta->last_preq +
+ min_preq_int_jiff(sdata));
+}
+
+/**
+ * mesh_path_start_discovery - launch a path discovery from the PREQ queue
+ *
+ * @dev: local mesh interface
+ */
+void mesh_path_start_discovery(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata =
+ IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct mesh_preq_queue *preq_node;
+ struct mesh_path *mpath;
+ u8 ttl, dst_flags;
+ u32 lifetime;
+
+ spin_lock(&ifsta->mesh_preq_queue_lock);
+ if (!ifsta->preq_queue_len ||
+ time_before(jiffies, ifsta->last_preq +
+ min_preq_int_jiff(sdata))) {
+ spin_unlock(&ifsta->mesh_preq_queue_lock);
+ return;
+ }
+
+ preq_node = list_first_entry(&ifsta->preq_queue.list,
+ struct mesh_preq_queue, list);
+ list_del(&preq_node->list);
+ --ifsta->preq_queue_len;
+ spin_unlock(&ifsta->mesh_preq_queue_lock);
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(preq_node->dst, dev);
+ if (!mpath)
+ goto enddiscovery;
+
+ spin_lock_bh(&mpath->state_lock);
+ if (preq_node->flags & PREQ_Q_F_START) {
+ if (mpath->flags & MESH_PATH_RESOLVING) {
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddiscovery;
+ } else {
+ mpath->flags &= ~MESH_PATH_RESOLVED;
+ mpath->flags |= MESH_PATH_RESOLVING;
+ mpath->discovery_retries = 0;
+ mpath->discovery_timeout = disc_timeout_jiff(sdata);
+ }
+ } else if (!(mpath->flags & MESH_PATH_RESOLVING) ||
+ mpath->flags & MESH_PATH_RESOLVED) {
+ mpath->flags &= ~MESH_PATH_RESOLVING;
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddiscovery;
+ }
+
+ ifsta->last_preq = jiffies;
+
+ if (time_after(jiffies, ifsta->last_dsn_update +
+ net_traversal_jiffies(sdata)) ||
+ time_before(jiffies, ifsta->last_dsn_update)) {
+ ++ifsta->dsn;
+ sdata->u.sta.last_dsn_update = jiffies;
+ }
+ lifetime = default_lifetime(sdata);
+ ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+ if (ttl == 0) {
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddiscovery;
+ }
+
+ if (preq_node->flags & PREQ_Q_F_REFRESH)
+ dst_flags = MP_F_DO;
+ else
+ dst_flags = MP_F_RF;
+
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_sel_frame_tx(MPATH_PREQ, 0, dev->dev_addr,
+ cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst,
+ cpu_to_le32(mpath->dsn), dev->broadcast, 0,
+ ttl, cpu_to_le32(lifetime), 0,
+ cpu_to_le32(ifsta->preq_id++), dev);
+ mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
+
+enddiscovery:
+ rcu_read_unlock();
+ kfree(preq_node);
+}
+
+/**
+ * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame
+ *
+ * @next_hop: output argument for next hop address
+ * @skb: frame to be sent
+ * @dev: network device the frame will be sent through
+ *
+ * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
+ * found, the function will start a path discovery and queue the frame so it is
+ * sent when the path is resolved. This means the caller must not free the skb
+ * in this case.
+ */
+int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sk_buff *skb_to_free = NULL;
+ struct mesh_path *mpath;
+ int err = 0;
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(skb->data, dev);
+
+ if (!mpath) {
+ mesh_path_add(skb->data, dev);
+ mpath = mesh_path_lookup(skb->data, dev);
+ if (!mpath) {
+ dev_kfree_skb(skb);
+ sdata->u.sta.mshstats.dropped_frames_no_route++;
+ err = -ENOSPC;
+ goto endlookup;
+ }
+ }
+
+ if (mpath->flags & MESH_PATH_ACTIVE) {
+ if (time_after(jiffies, mpath->exp_time -
+ msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time))
+ && skb->pkt_type != PACKET_OTHERHOST
+ && !(mpath->flags & MESH_PATH_RESOLVING)
+ && !(mpath->flags & MESH_PATH_FIXED)) {
+ mesh_queue_preq(mpath,
+ PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+ }
+ memcpy(next_hop, mpath->next_hop->addr,
+ ETH_ALEN);
+ } else {
+ if (!(mpath->flags & MESH_PATH_RESOLVING)) {
+ /* Start discovery only if it is not running yet */
+ mesh_queue_preq(mpath, PREQ_Q_F_START);
+ }
+
+ if (skb_queue_len(&mpath->frame_queue) >=
+ MESH_FRAME_QUEUE_LEN) {
+ skb_to_free = mpath->frame_queue.next;
+ skb_unlink(skb_to_free, &mpath->frame_queue);
+ }
+
+ skb_queue_tail(&mpath->frame_queue, skb);
+ if (skb_to_free)
+ mesh_path_discard_frame(skb_to_free, dev);
+ err = -ENOENT;
+ }
+
+endlookup:
+ rcu_read_unlock();
+ return err;
+}
+
+void mesh_path_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct mesh_path *mpath;
+
+ rcu_read_lock();
+ mpath = (struct mesh_path *) data;
+ mpath = rcu_dereference(mpath);
+ if (!mpath)
+ goto endmpathtimer;
+ spin_lock_bh(&mpath->state_lock);
+ sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+ if (mpath->flags & MESH_PATH_RESOLVED ||
+ (!(mpath->flags & MESH_PATH_RESOLVING)))
+ mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
+ else if (mpath->discovery_retries < max_preq_retries(sdata)) {
+ ++mpath->discovery_retries;
+ mpath->discovery_timeout *= 2;
+ mesh_queue_preq(mpath, 0);
+ } else {
+ mpath->flags = 0;
+ mpath->exp_time = jiffies;
+ mesh_path_flush_pending(mpath);
+ }
+
+ spin_unlock_bh(&mpath->state_lock);
+endmpathtimer:
+ rcu_read_unlock();
+}
--- /dev/null
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author: Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "mesh.h"
+
+/* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
+#define INIT_PATHS_SIZE_ORDER 2
+
+/* Keep the mean chain length below this constant */
+#define MEAN_CHAIN_LEN 2
+
+#define MPATH_EXPIRED(mpath) ((mpath->flags & MESH_PATH_ACTIVE) && \
+ time_after(jiffies, mpath->exp_time) && \
+ !(mpath->flags & MESH_PATH_FIXED))
+
+struct mpath_node {
+ struct hlist_node list;
+ struct rcu_head rcu;
+ /* This indirection allows two different tables to point to the same
+ * mesh_path structure, useful when resizing
+ */
+ struct mesh_path *mpath;
+};
+
+static struct mesh_table *mesh_paths;
+
+/* This lock will have the grow table function as writer and add / delete nodes
+ * as readers. When reading the table (i.e. doing lookups) we are well protected
+ * by RCU
+ */
+static DEFINE_RWLOCK(pathtbl_resize_lock);
+
+/**
+ *
+ * mesh_path_assign_nexthop - update mesh path next hop
+ *
+ * @mpath: mesh path to update
+ * @sta: next hop to assign
+ *
+ * Locking: mpath->state_lock must be held when calling this function
+ */
+void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
+{
+ rcu_assign_pointer(mpath->next_hop, sta);
+}
+
+
+/**
+ * mesh_path_lookup - look up a path in the mesh path table
+ * @dst: hardware address (ETH_ALEN length) of destination
+ * @dev: local interface
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev)
+{
+ struct mesh_path *mpath;
+ struct hlist_node *n;
+ struct hlist_head *bucket;
+ struct mesh_table *tbl;
+ struct mpath_node *node;
+
+ tbl = rcu_dereference(mesh_paths);
+
+ bucket = &tbl->hash_buckets[mesh_table_hash(dst, dev, tbl)];
+ hlist_for_each_entry_rcu(node, n, bucket, list) {
+ mpath = node->mpath;
+ if (mpath->dev == dev &&
+ memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
+ if (MPATH_EXPIRED(mpath)) {
+ spin_lock_bh(&mpath->state_lock);
+ if (MPATH_EXPIRED(mpath))
+ mpath->flags &= ~MESH_PATH_ACTIVE;
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ return mpath;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
+ * @idx: index
+ * @dev: local interface, or NULL for all entries
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev)
+{
+ struct mpath_node *node;
+ struct hlist_node *p;
+ int i;
+ int j = 0;
+
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ if (dev && node->mpath->dev != dev)
+ continue;
+ if (j++ == idx) {
+ if (MPATH_EXPIRED(node->mpath)) {
+ spin_lock_bh(&node->mpath->state_lock);
+ if (MPATH_EXPIRED(node->mpath))
+ node->mpath->flags &= ~MESH_PATH_ACTIVE;
+ spin_unlock_bh(&node->mpath->state_lock);
+ }
+ return node->mpath;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * mesh_path_add - allocate and add a new path to the mesh path table
+ * @addr: destination address of the path (ETH_ALEN length)
+ * @dev: local interface
+ *
+ * Returns: 0 on sucess
+ *
+ * State: the initial state of the new path is set to 0
+ */
+int mesh_path_add(u8 *dst, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath, *new_mpath;
+ struct mpath_node *node, *new_node;
+ struct hlist_head *bucket;
+ struct hlist_node *n;
+ int grow = 0;
+ int err = 0;
+ u32 hash_idx;
+
+ if (memcmp(dst, dev->dev_addr, ETH_ALEN) == 0)
+ /* never add ourselves as neighbours */
+ return -ENOTSUPP;
+
+ if (is_multicast_ether_addr(dst))
+ return -ENOTSUPP;
+
+ if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
+ return -ENOSPC;
+
+ read_lock(&pathtbl_resize_lock);
+
+ new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
+ if (!new_mpath) {
+ atomic_dec(&sdata->u.sta.mpaths);
+ err = -ENOMEM;
+ goto endadd2;
+ }
+ memcpy(new_mpath->dst, dst, ETH_ALEN);
+ new_mpath->dev = dev;
+ new_mpath->flags = 0;
+ skb_queue_head_init(&new_mpath->frame_queue);
+ new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+ new_node->mpath = new_mpath;
+ new_mpath->timer.data = (unsigned long) new_mpath;
+ new_mpath->timer.function = mesh_path_timer;
+ new_mpath->exp_time = jiffies;
+ spin_lock_init(&new_mpath->state_lock);
+ init_timer(&new_mpath->timer);
+
+ hash_idx = mesh_table_hash(dst, dev, mesh_paths);
+ bucket = &mesh_paths->hash_buckets[hash_idx];
+
+ spin_lock(&mesh_paths->hashwlock[hash_idx]);
+
+ hlist_for_each_entry(node, n, bucket, list) {
+ mpath = node->mpath;
+ if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN)
+ == 0) {
+ err = -EEXIST;
+ atomic_dec(&sdata->u.sta.mpaths);
+ kfree(new_node);
+ kfree(new_mpath);
+ goto endadd;
+ }
+ }
+
+ hlist_add_head_rcu(&new_node->list, bucket);
+ if (atomic_inc_return(&mesh_paths->entries) >=
+ mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
+ grow = 1;
+
+endadd:
+ spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+endadd2:
+ read_unlock(&pathtbl_resize_lock);
+ if (!err && grow) {
+ struct mesh_table *oldtbl, *newtbl;
+
+ write_lock(&pathtbl_resize_lock);
+ oldtbl = mesh_paths;
+ newtbl = mesh_table_grow(mesh_paths);
+ if (!newtbl) {
+ write_unlock(&pathtbl_resize_lock);
+ return -ENOMEM;
+ }
+ rcu_assign_pointer(mesh_paths, newtbl);
+ synchronize_rcu();
+ mesh_table_free(oldtbl, false);
+ write_unlock(&pathtbl_resize_lock);
+ }
+ return err;
+}
+
+
+/**
+ * mesh_plink_broken - deactivates paths and sends perr when a link breaks
+ *
+ * @sta: broken peer link
+ *
+ * This function must be called from the rate control algorithm if enough
+ * delivery errors suggest that a peer link is no longer usable.
+ */
+void mesh_plink_broken(struct sta_info *sta)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_node *p;
+ struct net_device *dev = sta->sdata->dev;
+ int i;
+
+ rcu_read_lock();
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ mpath = node->mpath;
+ spin_lock_bh(&mpath->state_lock);
+ if (mpath->next_hop == sta &&
+ mpath->flags & MESH_PATH_ACTIVE &&
+ !(mpath->flags & MESH_PATH_FIXED)) {
+ mpath->flags &= ~MESH_PATH_ACTIVE;
+ ++mpath->dsn;
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_error_tx(mpath->dst,
+ cpu_to_le32(mpath->dsn),
+ dev->broadcast, dev);
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(mesh_plink_broken);
+
+/**
+ * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
+ *
+ * @sta - mesh peer to match
+ *
+ * RCU notes: this function is called when a mesh plink transitions from
+ * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that
+ * allows path creation. This will happen before the sta can be freed (because
+ * sta_info_destroy() calls this) so any reader in a rcu read block will be
+ * protected against the plink disappearing.
+ */
+void mesh_path_flush_by_nexthop(struct sta_info *sta)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_node *p;
+ int i;
+
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ mpath = node->mpath;
+ if (mpath->next_hop == sta)
+ mesh_path_del(mpath->dst, mpath->dev);
+ }
+}
+
+void mesh_path_flush(struct net_device *dev)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_node *p;
+ int i;
+
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ mpath = node->mpath;
+ if (mpath->dev == dev)
+ mesh_path_del(mpath->dst, mpath->dev);
+ }
+}
+
+static void mesh_path_node_reclaim(struct rcu_head *rp)
+{
+ struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
+ struct ieee80211_sub_if_data *sdata =
+ IEEE80211_DEV_TO_SUB_IF(node->mpath->dev);
+
+ del_timer_sync(&node->mpath->timer);
+ atomic_dec(&sdata->u.sta.mpaths);
+ kfree(node->mpath);
+ kfree(node);
+}
+
+/**
+ * mesh_path_del - delete a mesh path from the table
+ *
+ * @addr: dst address (ETH_ALEN length)
+ * @dev: local interface
+ *
+ * Returns: 0 if succesful
+ */
+int mesh_path_del(u8 *addr, struct net_device *dev)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_head *bucket;
+ struct hlist_node *n;
+ int hash_idx;
+ int err = 0;
+
+ read_lock(&pathtbl_resize_lock);
+ hash_idx = mesh_table_hash(addr, dev, mesh_paths);
+ bucket = &mesh_paths->hash_buckets[hash_idx];
+
+ spin_lock(&mesh_paths->hashwlock[hash_idx]);
+ hlist_for_each_entry(node, n, bucket, list) {
+ mpath = node->mpath;
+ if (mpath->dev == dev &&
+ memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
+ spin_lock_bh(&mpath->state_lock);
+ mpath->flags |= MESH_PATH_RESOLVING;
+ hlist_del_rcu(&node->list);
+ call_rcu(&node->rcu, mesh_path_node_reclaim);
+ atomic_dec(&mesh_paths->entries);
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddel;
+ }
+ }
+
+ err = -ENXIO;
+enddel:
+ spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+ read_unlock(&pathtbl_resize_lock);
+ return err;
+}
+
+/**
+ * mesh_path_tx_pending - sends pending frames in a mesh path queue
+ *
+ * @mpath: mesh path to activate
+ *
+ * Locking: the state_lock of the mpath structure must NOT be held when calling
+ * this function.
+ */
+void mesh_path_tx_pending(struct mesh_path *mpath)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&mpath->frame_queue)) &&
+ (mpath->flags & MESH_PATH_ACTIVE))
+ dev_queue_xmit(skb);
+}
+
+/**
+ * mesh_path_discard_frame - discard a frame whose path could not be resolved
+ *
+ * @skb: frame to discard
+ * @dev: network device the frame was to be sent through
+ *
+ * If the frame was beign forwarded from another MP, a PERR frame will be sent
+ * to the precursor.
+ *
+ * Locking: the function must me called within a rcu_read_lock region
+ */
+void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+ u32 dsn = 0;
+
+ if (skb->pkt_type == PACKET_OTHERHOST) {
+ struct ieee80211s_hdr *prev_meshhdr;
+ int mshhdrlen;
+ u8 *ra, *da;
+
+ prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb);
+ mshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr);
+ da = skb->data;
+ ra = MESH_PREQ(skb);
+ mpath = mesh_path_lookup(da, dev);
+ if (mpath)
+ dsn = ++mpath->dsn;
+ mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, dev);
+ }
+
+ kfree_skb(skb);
+ sdata->u.sta.mshstats.dropped_frames_no_route++;
+}
+
+/**
+ * mesh_path_flush_pending - free the pending queue of a mesh path
+ *
+ * @mpath: mesh path whose queue has to be freed
+ *
+ * Locking: the function must me called withing a rcu_read_lock region
+ */
+void mesh_path_flush_pending(struct mesh_path *mpath)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct sk_buff *skb;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+
+ while ((skb = skb_dequeue(&mpath->frame_queue)) &&
+ (mpath->flags & MESH_PATH_ACTIVE))
+ mesh_path_discard_frame(skb, mpath->dev);
+}
+
+/**
+ * mesh_path_fix_nexthop - force a specific next hop for a mesh path
+ *
+ * @mpath: the mesh path to modify
+ * @next_hop: the next hop to force
+ *
+ * Locking: this function must be called holding mpath->state_lock
+ */
+void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop)
+{
+ spin_lock_bh(&mpath->state_lock);
+ mesh_path_assign_nexthop(mpath, next_hop);
+ mpath->dsn = 0xffff;
+ mpath->metric = 0;
+ mpath->hop_count = 0;
+ mpath->exp_time = 0;
+ mpath->flags |= MESH_PATH_FIXED;
+ mesh_path_activate(mpath);
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_tx_pending(mpath);
+}
+
+static void mesh_path_node_free(struct hlist_node *p, bool free_leafs)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node = hlist_entry(p, struct mpath_node, list);
+ mpath = node->mpath;
+ hlist_del_rcu(p);
+ synchronize_rcu();
+ if (free_leafs)
+ kfree(mpath);
+ kfree(node);
+}
+
+static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node, *new_node;
+ u32 hash_idx;
+
+ node = hlist_entry(p, struct mpath_node, list);
+ mpath = node->mpath;
+ new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+ new_node->mpath = mpath;
+ hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl);
+ hlist_add_head(&new_node->list,
+ &newtbl->hash_buckets[hash_idx]);
+}
+
+int mesh_pathtbl_init(void)
+{
+ mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+ mesh_paths->free_node = &mesh_path_node_free;
+ mesh_paths->copy_node = &mesh_path_node_copy;
+ mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
+ if (!mesh_paths)
+ return -ENOMEM;
+ return 0;
+}
+
+void mesh_path_expire(struct net_device *dev)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_node *p;
+ int i;
+
+ read_lock(&pathtbl_resize_lock);
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ if (node->mpath->dev != dev)
+ continue;
+ mpath = node->mpath;
+ spin_lock_bh(&mpath->state_lock);
+ if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
+ (!(mpath->flags & MESH_PATH_FIXED)) &&
+ time_after(jiffies,
+ mpath->exp_time + MESH_PATH_EXPIRE)) {
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_del(mpath->dst, mpath->dev);
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ read_unlock(&pathtbl_resize_lock);
+}
+
+void mesh_pathtbl_unregister(void)
+{
+ mesh_table_free(mesh_paths, true);
+}
--- /dev/null
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author: Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "mesh.h"
+
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
+#else
+#define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
+#endif
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+#define PLINK_GET_FRAME_SUBTYPE(p) (p)
+#define PLINK_GET_LLID(p) (p + 1)
+#define PLINK_GET_PLID(p) (p + 3)
+
+#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
+ jiffies + HZ * t / 1000))
+
+/* Peer link cancel reasons, all subject to ANA approval */
+#define MESH_LINK_CANCELLED 2
+#define MESH_MAX_NEIGHBORS 3
+#define MESH_CAPABILITY_POLICY_VIOLATION 4
+#define MESH_CLOSE_RCVD 5
+#define MESH_MAX_RETRIES 6
+#define MESH_CONFIRM_TIMEOUT 7
+#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS 8
+#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9
+#define MESH_SECURITY_FAILED_VERIFICATION 10
+
+#define dot11MeshMaxRetries(s) (s->u.sta.mshcfg.dot11MeshMaxRetries)
+#define dot11MeshRetryTimeout(s) (s->u.sta.mshcfg.dot11MeshRetryTimeout)
+#define dot11MeshConfirmTimeout(s) (s->u.sta.mshcfg.dot11MeshConfirmTimeout)
+#define dot11MeshHoldingTimeout(s) (s->u.sta.mshcfg.dot11MeshHoldingTimeout)
+#define dot11MeshMaxPeerLinks(s) (s->u.sta.mshcfg.dot11MeshMaxPeerLinks)
+
+enum plink_frame_type {
+ PLINK_OPEN = 0,
+ PLINK_CONFIRM,
+ PLINK_CLOSE
+};
+
+enum plink_event {
+ PLINK_UNDEFINED,
+ OPN_ACPT,
+ OPN_RJCT,
+ OPN_IGNR,
+ CNF_ACPT,
+ CNF_RJCT,
+ CNF_IGNR,
+ CLS_ACPT,
+ CLS_IGNR
+};
+
+static inline
+void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
+{
+ atomic_inc(&sdata->u.sta.mshstats.estab_plinks);
+ mesh_accept_plinks_update(sdata);
+}
+
+static inline
+void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
+{
+ atomic_dec(&sdata->u.sta.mshstats.estab_plinks);
+ mesh_accept_plinks_update(sdata);
+}
+
+/**
+ * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
+ *
+ * @sta: mes peer link to restart
+ *
+ * Locking: this function must be called holding sta->plink_lock
+ */
+static inline void mesh_plink_fsm_restart(struct sta_info *sta)
+{
+ sta->plink_state = PLINK_LISTEN;
+ sta->llid = sta->plid = sta->reason = 0;
+ sta->plink_retries = 0;
+}
+
+static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
+ u8 *hw_addr, u64 rates)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ if (local->num_sta >= MESH_MAX_PLINKS)
+ return NULL;
+
+ sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC);
+ if (!sta)
+ return NULL;
+
+ sta->flags |= WLAN_STA_AUTHORIZED;
+ sta->supp_rates[local->hw.conf.channel->band] = rates;
+
+ return sta;
+}
+
+/**
+ * mesh_plink_deactivate - deactivate mesh peer link
+ *
+ * @sta: mesh peer link to deactivate
+ *
+ * All mesh paths with this peer as next hop will be flushed
+ *
+ * Locking: the caller must hold sta->plink_lock
+ */
+static void __mesh_plink_deactivate(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+ if (sta->plink_state == PLINK_ESTAB)
+ mesh_plink_dec_estab_count(sdata);
+ sta->plink_state = PLINK_BLOCKED;
+ mesh_path_flush_by_nexthop(sta);
+}
+
+/**
+ * __mesh_plink_deactivate - deactivate mesh peer link
+ *
+ * @sta: mesh peer link to deactivate
+ *
+ * All mesh paths with this peer as next hop will be flushed
+ */
+void mesh_plink_deactivate(struct sta_info *sta)
+{
+ spin_lock_bh(&sta->plink_lock);
+ __mesh_plink_deactivate(sta);
+ spin_unlock_bh(&sta->plink_lock);
+}
+
+static int mesh_plink_frame_tx(struct net_device *dev,
+ enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
+ __le16 reason) {
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ struct ieee80211_mgmt *mgmt;
+ bool include_plid = false;
+ u8 *pos;
+ int ie_len;
+
+ if (!skb)
+ return -1;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ /* 25 is the size of the common mgmt part (24) plus the size of the
+ * common action part (1)
+ */
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
+ memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+ memcpy(mgmt->da, da, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.action.category = PLINK_CATEGORY;
+ mgmt->u.action.u.plink_action.action_code = action;
+
+ if (action == PLINK_CLOSE)
+ mgmt->u.action.u.plink_action.aux = reason;
+ else {
+ mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
+ if (action == PLINK_CONFIRM) {
+ pos = skb_put(skb, 4);
+ /* two-byte status code followed by two-byte AID */
+ memset(pos, 0, 4);
+ }
+ mesh_mgmt_ies_add(skb, dev);
+ }
+
+ /* Add Peer Link Management element */
+ switch (action) {
+ case PLINK_OPEN:
+ ie_len = 3;
+ break;
+ case PLINK_CONFIRM:
+ ie_len = 5;
+ include_plid = true;
+ break;
+ case PLINK_CLOSE:
+ default:
+ if (!plid)
+ ie_len = 5;
+ else {
+ ie_len = 7;
+ include_plid = true;
+ }
+ break;
+ }
+
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PEER_LINK;
+ *pos++ = ie_len;
+ *pos++ = action;
+ memcpy(pos, &llid, 2);
+ if (include_plid) {
+ pos += 2;
+ memcpy(pos, &plid, 2);
+ }
+ if (action == PLINK_CLOSE) {
+ pos += 2;
+ memcpy(pos, &reason, 2);
+ }
+
+ ieee80211_sta_tx(dev, skb, 0);
+ return 0;
+}
+
+void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
+ bool peer_accepting_plinks)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, hw_addr);
+ if (!sta) {
+ sta = mesh_plink_alloc(sdata, hw_addr, rates);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+ if (sta_info_insert(sta)) {
+ sta_info_destroy(sta);
+ rcu_read_unlock();
+ return;
+ }
+ }
+
+ sta->last_rx = jiffies;
+ sta->supp_rates[local->hw.conf.channel->band] = rates;
+ if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
+ sdata->u.sta.accepting_plinks &&
+ sdata->u.sta.mshcfg.auto_open_plinks)
+ mesh_plink_open(sta);
+
+ rcu_read_unlock();
+}
+
+static void mesh_plink_timer(unsigned long data)
+{
+ struct sta_info *sta;
+ __le16 llid, plid, reason;
+ struct net_device *dev = NULL;
+ struct ieee80211_sub_if_data *sdata;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ /*
+ * This STA is valid because sta_info_destroy() will
+ * del_timer_sync() this timer after having made sure
+ * it cannot be readded (by deleting the plink.)
+ */
+ sta = (struct sta_info *) data;
+
+ spin_lock_bh(&sta->plink_lock);
+ if (sta->ignore_plink_timer) {
+ sta->ignore_plink_timer = false;
+ spin_unlock_bh(&sta->plink_lock);
+ return;
+ }
+ mpl_dbg("Mesh plink timer for %s fired on state %d\n",
+ print_mac(mac, sta->addr), sta->plink_state);
+ reason = 0;
+ llid = sta->llid;
+ plid = sta->plid;
+ sdata = sta->sdata;
+ dev = sdata->dev;
+
+ switch (sta->plink_state) {
+ case PLINK_OPN_RCVD:
+ case PLINK_OPN_SNT:
+ /* retry timer */
+ if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
+ u32 rand;
+ mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n",
+ print_mac(mac, sta->addr),
+ sta->plink_retries, sta->plink_timeout);
+ get_random_bytes(&rand, sizeof(u32));
+ sta->plink_timeout = sta->plink_timeout +
+ rand % sta->plink_timeout;
+ ++sta->plink_retries;
+ mod_plink_timer(sta, sta->plink_timeout);
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
+ 0, 0);
+ break;
+ }
+ reason = cpu_to_le16(MESH_MAX_RETRIES);
+ /* fall through on else */
+ case PLINK_CNF_RCVD:
+ /* confirm timer */
+ if (!reason)
+ reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
+ sta->plink_state = PLINK_HOLDING;
+ mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
+ reason);
+ break;
+ case PLINK_HOLDING:
+ /* holding timer */
+ del_timer(&sta->plink_timer);
+ mesh_plink_fsm_restart(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+}
+
+static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
+{
+ sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
+ sta->plink_timer.data = (unsigned long) sta;
+ sta->plink_timer.function = mesh_plink_timer;
+ sta->plink_timeout = timeout;
+ add_timer(&sta->plink_timer);
+}
+
+int mesh_plink_open(struct sta_info *sta)
+{
+ __le16 llid;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ spin_lock_bh(&sta->plink_lock);
+ get_random_bytes(&llid, 2);
+ sta->llid = llid;
+ if (sta->plink_state != PLINK_LISTEN) {
+ spin_unlock_bh(&sta->plink_lock);
+ return -EBUSY;
+ }
+ sta->plink_state = PLINK_OPN_SNT;
+ mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
+ spin_unlock_bh(&sta->plink_lock);
+ mpl_dbg("Mesh plink: starting establishment with %s\n",
+ print_mac(mac, sta->addr));
+
+ return mesh_plink_frame_tx(sdata->dev, PLINK_OPEN,
+ sta->addr, llid, 0, 0);
+}
+
+void mesh_plink_block(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ spin_lock_bh(&sta->plink_lock);
+ __mesh_plink_deactivate(sta);
+ sta->plink_state = PLINK_BLOCKED;
+ spin_unlock_bh(&sta->plink_lock);
+}
+
+int mesh_plink_close(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ __le16 llid, plid, reason;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ mpl_dbg("Mesh plink: closing link with %s\n",
+ print_mac(mac, sta->addr));
+ spin_lock_bh(&sta->plink_lock);
+ sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
+ reason = sta->reason;
+
+ if (sta->plink_state == PLINK_LISTEN ||
+ sta->plink_state == PLINK_BLOCKED) {
+ mesh_plink_fsm_restart(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ return 0;
+ } else if (sta->plink_state == PLINK_ESTAB) {
+ __mesh_plink_deactivate(sta);
+ /* The timer should not be running */
+ mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
+ } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ sta->plink_state = PLINK_HOLDING;
+ llid = sta->llid;
+ plid = sta->plid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ return 0;
+}
+
+void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+ size_t len, struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee802_11_elems elems;
+ struct sta_info *sta;
+ enum plink_event event;
+ enum plink_frame_type ftype;
+ size_t baselen;
+ u8 ie_len;
+ u8 *baseaddr;
+ __le16 plid, llid, reason;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ if (is_multicast_ether_addr(mgmt->da)) {
+ mpl_dbg("Mesh plink: ignore frame from multicast address");
+ return;
+ }
+
+ baseaddr = mgmt->u.action.u.plink_action.variable;
+ baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
+ if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) {
+ baseaddr += 4;
+ baselen -= 4;
+ }
+ ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
+ if (!elems.peer_link) {
+ mpl_dbg("Mesh plink: missing necessary peer link ie\n");
+ return;
+ }
+
+ ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link));
+ ie_len = elems.peer_link_len;
+ if ((ftype == PLINK_OPEN && ie_len != 3) ||
+ (ftype == PLINK_CONFIRM && ie_len != 5) ||
+ (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) {
+ mpl_dbg("Mesh plink: incorrect plink ie length\n");
+ return;
+ }
+
+ if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) {
+ mpl_dbg("Mesh plink: missing necessary ie\n");
+ return;
+ }
+ /* Note the lines below are correct, the llid in the frame is the plid
+ * from the point of view of this host.
+ */
+ memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2);
+ if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7))
+ memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, mgmt->sa);
+ if (!sta && ftype != PLINK_OPEN) {
+ mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
+ rcu_read_unlock();
+ return;
+ }
+
+ if (sta && sta->plink_state == PLINK_BLOCKED) {
+ rcu_read_unlock();
+ return;
+ }
+
+ /* Now we will figure out the appropriate event... */
+ event = PLINK_UNDEFINED;
+ if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, dev))) {
+ switch (ftype) {
+ case PLINK_OPEN:
+ event = OPN_RJCT;
+ break;
+ case PLINK_CONFIRM:
+ event = CNF_RJCT;
+ break;
+ case PLINK_CLOSE:
+ /* avoid warning */
+ break;
+ }
+ spin_lock_bh(&sta->plink_lock);
+ } else if (!sta) {
+ /* ftype == PLINK_OPEN */
+ u64 rates;
+ if (!mesh_plink_free_count(sdata)) {
+ mpl_dbg("Mesh plink error: no more free plinks\n");
+ rcu_read_unlock();
+ return;
+ }
+
+ rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
+ sta = mesh_plink_alloc(sdata, mgmt->sa, rates);
+ if (!sta) {
+ mpl_dbg("Mesh plink error: plink table full\n");
+ rcu_read_unlock();
+ return;
+ }
+ if (sta_info_insert(sta)) {
+ sta_info_destroy(sta);
+ rcu_read_unlock();
+ return;
+ }
+ event = OPN_ACPT;
+ spin_lock_bh(&sta->plink_lock);
+ } else {
+ spin_lock_bh(&sta->plink_lock);
+ switch (ftype) {
+ case PLINK_OPEN:
+ if (!mesh_plink_free_count(sdata) ||
+ (sta->plid && sta->plid != plid))
+ event = OPN_IGNR;
+ else
+ event = OPN_ACPT;
+ break;
+ case PLINK_CONFIRM:
+ if (!mesh_plink_free_count(sdata) ||
+ (sta->llid != llid || sta->plid != plid))
+ event = CNF_IGNR;
+ else
+ event = CNF_ACPT;
+ break;
+ case PLINK_CLOSE:
+ if (sta->plink_state == PLINK_ESTAB)
+ /* Do not check for llid or plid. This does not
+ * follow the standard but since multiple plinks
+ * per sta are not supported, it is necessary in
+ * order to avoid a livelock when MP A sees an
+ * establish peer link to MP B but MP B does not
+ * see it. This can be caused by a timeout in
+ * B's peer link establishment or B beign
+ * restarted.
+ */
+ event = CLS_ACPT;
+ else if (sta->plid != plid)
+ event = CLS_IGNR;
+ else if (ie_len == 7 && sta->llid != llid)
+ event = CLS_IGNR;
+ else
+ event = CLS_ACPT;
+ break;
+ default:
+ mpl_dbg("Mesh plink: unknown frame subtype\n");
+ spin_unlock_bh(&sta->plink_lock);
+ rcu_read_unlock();
+ return;
+ }
+ }
+
+ mpl_dbg("Mesh plink (peer, state, llid, plid, event): %s %d %d %d %d\n",
+ print_mac(mac, mgmt->sa), sta->plink_state,
+ le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
+ event);
+ reason = 0;
+ switch (sta->plink_state) {
+ /* spin_unlock as soon as state is updated at each case */
+ case PLINK_LISTEN:
+ switch (event) {
+ case CLS_ACPT:
+ mesh_plink_fsm_restart(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ case OPN_ACPT:
+ sta->plink_state = PLINK_OPN_RCVD;
+ sta->plid = plid;
+ get_random_bytes(&llid, 2);
+ sta->llid = llid;
+ mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
+ 0, 0);
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr,
+ llid, plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+
+ case PLINK_OPN_SNT:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ sta->reason = reason;
+ sta->plink_state = PLINK_HOLDING;
+ if (!mod_plink_timer(sta,
+ dot11MeshHoldingTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ case OPN_ACPT:
+ /* retry timer is left untouched */
+ sta->plink_state = PLINK_OPN_RCVD;
+ sta->plid = plid;
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+ plid, 0);
+ break;
+ case CNF_ACPT:
+ sta->plink_state = PLINK_CNF_RCVD;
+ if (!mod_plink_timer(sta,
+ dot11MeshConfirmTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+
+ case PLINK_OPN_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ sta->reason = reason;
+ sta->plink_state = PLINK_HOLDING;
+ if (!mod_plink_timer(sta,
+ dot11MeshHoldingTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ case OPN_ACPT:
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+ plid, 0);
+ break;
+ case CNF_ACPT:
+ del_timer(&sta->plink_timer);
+ sta->plink_state = PLINK_ESTAB;
+ mesh_plink_inc_estab_count(sdata);
+ spin_unlock_bh(&sta->plink_lock);
+ mpl_dbg("Mesh plink with %s ESTABLISHED\n",
+ print_mac(mac, sta->addr));
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+
+ case PLINK_CNF_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ sta->reason = reason;
+ sta->plink_state = PLINK_HOLDING;
+ if (!mod_plink_timer(sta,
+ dot11MeshHoldingTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ case OPN_ACPT:
+ del_timer(&sta->plink_timer);
+ sta->plink_state = PLINK_ESTAB;
+ mesh_plink_inc_estab_count(sdata);
+ spin_unlock_bh(&sta->plink_lock);
+ mpl_dbg("Mesh plink with %s ESTABLISHED\n",
+ print_mac(mac, sta->addr));
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+ plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+
+ case PLINK_ESTAB:
+ switch (event) {
+ case CLS_ACPT:
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ sta->reason = reason;
+ __mesh_plink_deactivate(sta);
+ sta->plink_state = PLINK_HOLDING;
+ llid = sta->llid;
+ mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ case OPN_ACPT:
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+ plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+ case PLINK_HOLDING:
+ switch (event) {
+ case CLS_ACPT:
+ if (del_timer(&sta->plink_timer))
+ sta->ignore_plink_timer = 1;
+ mesh_plink_fsm_restart(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ case OPN_ACPT:
+ case CNF_ACPT:
+ case OPN_RJCT:
+ case CNF_RJCT:
+ llid = sta->llid;
+ reason = sta->reason;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ }
+ break;
+ default:
+ /* should not get here, PLINK_BLOCKED is dealt with at the
+ * beggining of the function
+ */
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+
+ rcu_read_unlock();
+}
#include <linux/debugfs.h>
#include <net/mac80211.h>
#include "ieee80211_rate.h"
-
+#include "mesh.h"
#include "rc80211_pid.h"
* RC_PID_ARITH_SHIFT.
*/
+
/* Adjust the rate while ensuring that we won't switch to a lower rate if it
* exhibited a worse failed frames behaviour and we'll choose the highest rate
* whose failed frames behaviour is not worse than the one of the original rate
struct rc_pid_rateinfo *rinfo)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_hw_mode *mode;
- int cur_sorted, new_sorted, probe, tmp, n_bitrates;
- int cur = sta->txrate;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ struct ieee80211_supported_band *sband;
+ int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
+ int cur = sta->txrate_idx;
- mode = local->oper_hw_mode;
- n_bitrates = mode->num_rates;
+ sdata = sta->sdata;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ band = sband->band;
+ n_bitrates = sband->n_bitrates;
/* Map passed arguments to sorted values. */
cur_sorted = rinfo[cur].rev_index;
/* Ensure that the rate decrease isn't disadvantageous. */
for (probe = cur_sorted; probe >= new_sorted; probe--)
if (rinfo[probe].diff <= rinfo[cur_sorted].diff &&
- rate_supported(sta, mode, rinfo[probe].index))
+ rate_supported(sta, band, rinfo[probe].index))
tmp = probe;
} else {
/* Look for rate increase with zero (or below) cost. */
for (probe = new_sorted + 1; probe < n_bitrates; probe++)
if (rinfo[probe].diff <= rinfo[new_sorted].diff &&
- rate_supported(sta, mode, rinfo[probe].index))
+ rate_supported(sta, band, rinfo[probe].index))
tmp = probe;
}
/* Fit the rate found to the nearest supported rate. */
do {
- if (rate_supported(sta, mode, rinfo[tmp].index)) {
- sta->txrate = rinfo[tmp].index;
+ if (rate_supported(sta, band, rinfo[tmp].index)) {
+ sta->txrate_idx = rinfo[tmp].index;
break;
}
if (adj < 0)
#ifdef CONFIG_MAC80211_DEBUGFS
rate_control_pid_event_rate_change(
&((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
- cur, mode->rates[cur].rate);
+ sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate);
#endif
}
struct ieee80211_local *local,
struct sta_info *sta)
{
+#ifdef CONFIG_MAC80211_MESH
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+#endif
struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
- struct ieee80211_hw_mode *mode;
+ struct ieee80211_supported_band *sband;
u32 pf;
s32 err_avg;
u32 err_prop;
int adj, i, j, tmp;
unsigned long period;
- mode = local->oper_hw_mode;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
spinfo = sta->rate_ctrl_priv;
/* In case nothing happened during the previous control interval, turn
pf = spinfo->last_pf;
else {
pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
+#ifdef CONFIG_MAC80211_MESH
+ if (pf == 100 &&
+ sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ mesh_plink_broken(sta);
+#endif
pf <<= RC_PID_ARITH_SHIFT;
+ sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
+ >> RC_PID_ARITH_SHIFT;
}
spinfo->tx_num_xmit = 0;
spinfo->tx_num_failed = 0;
/* If we just switched rate, update the rate behaviour info. */
- if (pinfo->oldrate != sta->txrate) {
+ if (pinfo->oldrate != sta->txrate_idx) {
i = rinfo[pinfo->oldrate].rev_index;
- j = rinfo[sta->txrate].rev_index;
+ j = rinfo[sta->txrate_idx].rev_index;
tmp = (pf - spinfo->last_pf);
tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT);
rinfo[j].diff = rinfo[i].diff + tmp;
- pinfo->oldrate = sta->txrate;
+ pinfo->oldrate = sta->txrate_idx;
}
- rate_control_pid_normalize(pinfo, mode->num_rates);
+ rate_control_pid_normalize(pinfo, sband->n_bitrates);
/* Compute the proportional, integral and derivative errors. */
err_prop = (pinfo->target << RC_PID_ARITH_SHIFT) - pf;
struct sta_info *sta;
struct rc_pid_sta_info *spinfo;
unsigned long period;
+ struct ieee80211_supported_band *sband;
+
+ rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
if (!sta)
- return;
+ goto unlock;
/* Don't update the state if we're not controlling the rate. */
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ sdata = sta->sdata;
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
- sta->txrate = sdata->bss->max_ratectrl_rateidx;
- return;
+ sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
+ goto unlock;
}
/* Ignore all frames that were sent with a different rate than the rate
* we currently advise mac80211 to use. */
- if (status->control.rate != &local->oper_hw_mode->rates[sta->txrate])
- goto ignore;
+ if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
+ goto unlock;
spinfo = sta->rate_ctrl_priv;
spinfo->tx_num_xmit++;
sta->tx_num_consecutive_failures++;
sta->tx_num_mpdu_fail++;
} else {
- sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
- sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
- sta->last_ack_rssi[2] = status->ack_signal;
sta->tx_num_consecutive_failures = 0;
sta->tx_num_mpdu_ok++;
}
if (time_after(jiffies, spinfo->last_sample + period))
rate_control_pid_sample(pinfo, local, sta);
-ignore:
- sta_info_put(sta);
+ unlock:
+ rcu_read_unlock();
}
static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
- struct ieee80211_hw_mode *mode,
+ struct ieee80211_supported_band *sband,
struct sk_buff *skb,
struct rate_selection *sel)
{
int rateidx;
u16 fc;
+ rcu_read_lock();
+
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest
fc = le16_to_cpu(hdr->frame_control);
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
is_multicast_ether_addr(hdr->addr1) || !sta) {
- sel->rate = rate_lowest(local, mode, sta);
- if (sta)
- sta_info_put(sta);
+ sel->rate = rate_lowest(local, sband, sta);
+ rcu_read_unlock();
return;
}
/* If a forced rate is in effect, select it. */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
- sta->txrate = sdata->bss->force_unicast_rateidx;
+ sta->txrate_idx = sdata->bss->force_unicast_rateidx;
- rateidx = sta->txrate;
+ rateidx = sta->txrate_idx;
- if (rateidx >= mode->num_rates)
- rateidx = mode->num_rates - 1;
+ if (rateidx >= sband->n_bitrates)
+ rateidx = sband->n_bitrates - 1;
- sta->last_txrate = rateidx;
+ sta->last_txrate_idx = rateidx;
- sta_info_put(sta);
+ rcu_read_unlock();
- sel->rate = &mode->rates[rateidx];
+ sel->rate = &sband->bitrates[rateidx];
#ifdef CONFIG_MAC80211_DEBUGFS
rate_control_pid_event_tx_rate(
&((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
- rateidx, mode->rates[rateidx].rate);
+ rateidx, sband->bitrates[rateidx].bitrate);
#endif
}
* as we need to have IEEE 802.1X auth succeed immediately after assoc..
* Until that method is implemented, we will use the lowest supported
* rate as a workaround. */
- sta->txrate = rate_lowest_index(local, local->oper_hw_mode, sta);
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sta->txrate_idx = rate_lowest_index(local, sband, sta);
+ sta->fail_avg = 0;
}
static void *rate_control_pid_alloc(struct ieee80211_local *local)
{
struct rc_pid_info *pinfo;
struct rc_pid_rateinfo *rinfo;
- struct ieee80211_hw_mode *mode;
+ struct ieee80211_supported_band *sband;
int i, j, tmp;
bool s;
#ifdef CONFIG_MAC80211_DEBUGFS
struct rc_pid_debugfs_entries *de;
#endif
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC);
if (!pinfo)
return NULL;
- /* We can safely assume that oper_hw_mode won't change unless we get
+ /* We can safely assume that sband won't change unless we get
* reinitialized. */
- mode = local->oper_hw_mode;
- rinfo = kmalloc(sizeof(*rinfo) * mode->num_rates, GFP_ATOMIC);
+ rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC);
if (!rinfo) {
kfree(pinfo);
return NULL;
/* Sort the rates. This is optimized for the most common case (i.e.
* almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
* mapping too. */
- for (i = 0; i < mode->num_rates; i++) {
+ for (i = 0; i < sband->n_bitrates; i++) {
rinfo[i].index = i;
rinfo[i].rev_index = i;
if (pinfo->fast_start)
else
rinfo[i].diff = i * pinfo->norm_offset;
}
- for (i = 1; i < mode->num_rates; i++) {
+ for (i = 1; i < sband->n_bitrates; i++) {
s = 0;
- for (j = 0; j < mode->num_rates - i; j++)
- if (unlikely(mode->rates[rinfo[j].index].rate >
- mode->rates[rinfo[j + 1].index].rate)) {
+ for (j = 0; j < sband->n_bitrates - i; j++)
+ if (unlikely(sband->bitrates[rinfo[j].index].bitrate >
+ sband->bitrates[rinfo[j + 1].index].bitrate)) {
tmp = rinfo[j].index;
rinfo[j].index = rinfo[j + 1].index;
rinfo[j + 1].index = tmp;
+++ /dev/null
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/compiler.h>
-#include <linux/module.h>
-
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-#include "ieee80211_rate.h"
-#include "debugfs.h"
-
-
-/* This is a minimal implementation of TX rate controlling that can be used
- * as the default when no improved mechanisms are available. */
-
-#define RATE_CONTROL_NUM_DOWN 20
-#define RATE_CONTROL_NUM_UP 15
-
-#define RATE_CONTROL_EMERG_DEC 2
-#define RATE_CONTROL_INTERVAL (HZ / 20)
-#define RATE_CONTROL_MIN_TX 10
-
-static void rate_control_rate_inc(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_hw_mode *mode;
- int i = sta->txrate;
- int maxrate;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
- if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
- /* forced unicast rate - do not change STA rate */
- return;
- }
-
- mode = local->oper_hw_mode;
- maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
-
- if (i > mode->num_rates)
- i = mode->num_rates - 2;
-
- while (i + 1 < mode->num_rates) {
- i++;
- if (sta->supp_rates & BIT(i) &&
- mode->rates[i].flags & IEEE80211_RATE_SUPPORTED &&
- (maxrate < 0 || i <= maxrate)) {
- sta->txrate = i;
- break;
- }
- }
-}
-
-
-static void rate_control_rate_dec(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_hw_mode *mode;
- int i = sta->txrate;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
- if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
- /* forced unicast rate - do not change STA rate */
- return;
- }
-
- mode = local->oper_hw_mode;
- if (i > mode->num_rates)
- i = mode->num_rates;
-
- while (i > 0) {
- i--;
- if (sta->supp_rates & BIT(i) &&
- mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) {
- sta->txrate = i;
- break;
- }
- }
-}
-
-struct global_rate_control {
- int dummy;
-};
-
-struct sta_rate_control {
- unsigned long last_rate_change;
- u32 tx_num_failures;
- u32 tx_num_xmit;
-
- unsigned long avg_rate_update;
- u32 tx_avg_rate_sum;
- u32 tx_avg_rate_num;
-
-#ifdef CONFIG_MAC80211_DEBUGFS
- struct dentry *tx_avg_rate_sum_dentry;
- struct dentry *tx_avg_rate_num_dentry;
-#endif
-};
-
-
-static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct sta_info *sta;
- struct sta_rate_control *srctrl;
-
- sta = sta_info_get(local, hdr->addr1);
-
- if (!sta)
- return;
-
- srctrl = sta->rate_ctrl_priv;
- srctrl->tx_num_xmit++;
- if (status->excessive_retries) {
- srctrl->tx_num_failures++;
- sta->tx_retry_failed++;
- sta->tx_num_consecutive_failures++;
- sta->tx_num_mpdu_fail++;
- } else {
- sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
- sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
- sta->last_ack_rssi[2] = status->ack_signal;
- sta->tx_num_consecutive_failures = 0;
- sta->tx_num_mpdu_ok++;
- }
- sta->tx_retry_count += status->retry_count;
- sta->tx_num_mpdu_fail += status->retry_count;
-
- if (time_after(jiffies,
- srctrl->last_rate_change + RATE_CONTROL_INTERVAL) &&
- srctrl->tx_num_xmit > RATE_CONTROL_MIN_TX) {
- u32 per_failed;
- srctrl->last_rate_change = jiffies;
-
- per_failed = (100 * sta->tx_num_mpdu_fail) /
- (sta->tx_num_mpdu_fail + sta->tx_num_mpdu_ok);
- /* TODO: calculate average per_failed to make adjusting
- * parameters easier */
-#if 0
- if (net_ratelimit()) {
- printk(KERN_DEBUG "MPDU fail=%d ok=%d per_failed=%d\n",
- sta->tx_num_mpdu_fail, sta->tx_num_mpdu_ok,
- per_failed);
- }
-#endif
-
- /*
- * XXX: Make these configurable once we have an
- * interface to the rate control algorithms
- */
- if (per_failed > RATE_CONTROL_NUM_DOWN) {
- rate_control_rate_dec(local, sta);
- } else if (per_failed < RATE_CONTROL_NUM_UP) {
- rate_control_rate_inc(local, sta);
- }
- srctrl->tx_avg_rate_sum += status->control.rate->rate;
- srctrl->tx_avg_rate_num++;
- srctrl->tx_num_failures = 0;
- srctrl->tx_num_xmit = 0;
- } else if (sta->tx_num_consecutive_failures >=
- RATE_CONTROL_EMERG_DEC) {
- rate_control_rate_dec(local, sta);
- }
-
- if (srctrl->avg_rate_update + 60 * HZ < jiffies) {
- srctrl->avg_rate_update = jiffies;
- if (srctrl->tx_avg_rate_num > 0) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%s: STA %s Average rate: "
- "%d (%d/%d)\n",
- dev->name, print_mac(mac, sta->addr),
- srctrl->tx_avg_rate_sum /
- srctrl->tx_avg_rate_num,
- srctrl->tx_avg_rate_sum,
- srctrl->tx_avg_rate_num);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
- srctrl->tx_avg_rate_sum = 0;
- srctrl->tx_avg_rate_num = 0;
- }
- }
-
- sta_info_put(sta);
-}
-
-
-static void
-rate_control_simple_get_rate(void *priv, struct net_device *dev,
- struct ieee80211_hw_mode *mode,
- struct sk_buff *skb,
- struct rate_selection *sel)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct ieee80211_sub_if_data *sdata;
- struct sta_info *sta;
- int rateidx;
- u16 fc;
-
- sta = sta_info_get(local, hdr->addr1);
-
- /* Send management frames and broadcast/multicast data using lowest
- * rate. */
- fc = le16_to_cpu(hdr->frame_control);
- if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
- is_multicast_ether_addr(hdr->addr1) || !sta) {
- sel->rate = rate_lowest(local, mode, sta);
- if (sta)
- sta_info_put(sta);
- return;
- }
-
- /* If a forced rate is in effect, select it. */
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
- sta->txrate = sdata->bss->force_unicast_rateidx;
-
- rateidx = sta->txrate;
-
- if (rateidx >= mode->num_rates)
- rateidx = mode->num_rates - 1;
-
- sta->last_txrate = rateidx;
-
- sta_info_put(sta);
-
- sel->rate = &mode->rates[rateidx];
-}
-
-
-static void rate_control_simple_rate_init(void *priv, void *priv_sta,
- struct ieee80211_local *local,
- struct sta_info *sta)
-{
- struct ieee80211_hw_mode *mode;
- int i;
- sta->txrate = 0;
- mode = local->oper_hw_mode;
- /* TODO: This routine should consider using RSSI from previous packets
- * as we need to have IEEE 802.1X auth succeed immediately after assoc..
- * Until that method is implemented, we will use the lowest supported rate
- * as a workaround, */
- for (i = 0; i < mode->num_rates; i++) {
- if ((sta->supp_rates & BIT(i)) &&
- (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) {
- sta->txrate = i;
- break;
- }
- }
-}
-
-
-static void * rate_control_simple_alloc(struct ieee80211_local *local)
-{
- struct global_rate_control *rctrl;
-
- rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
-
- return rctrl;
-}
-
-
-static void rate_control_simple_free(void *priv)
-{
- struct global_rate_control *rctrl = priv;
- kfree(rctrl);
-}
-
-
-static void rate_control_simple_clear(void *priv)
-{
-}
-
-
-static void * rate_control_simple_alloc_sta(void *priv, gfp_t gfp)
-{
- struct sta_rate_control *rctrl;
-
- rctrl = kzalloc(sizeof(*rctrl), gfp);
-
- return rctrl;
-}
-
-
-static void rate_control_simple_free_sta(void *priv, void *priv_sta)
-{
- struct sta_rate_control *rctrl = priv_sta;
- kfree(rctrl);
-}
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-
-static int open_file_generic(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t sta_tx_avg_rate_sum_read(struct file *file,
- char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct sta_rate_control *srctrl = file->private_data;
- char buf[20];
-
- sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum);
- return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
-}
-
-static const struct file_operations sta_tx_avg_rate_sum_ops = {
- .read = sta_tx_avg_rate_sum_read,
- .open = open_file_generic,
-};
-
-static ssize_t sta_tx_avg_rate_num_read(struct file *file,
- char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct sta_rate_control *srctrl = file->private_data;
- char buf[20];
-
- sprintf(buf, "%d\n", srctrl->tx_avg_rate_num);
- return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
-}
-
-static const struct file_operations sta_tx_avg_rate_num_ops = {
- .read = sta_tx_avg_rate_num_read,
- .open = open_file_generic,
-};
-
-static void rate_control_simple_add_sta_debugfs(void *priv, void *priv_sta,
- struct dentry *dir)
-{
- struct sta_rate_control *srctrl = priv_sta;
-
- srctrl->tx_avg_rate_num_dentry =
- debugfs_create_file("rc_simple_sta_tx_avg_rate_num", 0400,
- dir, srctrl, &sta_tx_avg_rate_num_ops);
- srctrl->tx_avg_rate_sum_dentry =
- debugfs_create_file("rc_simple_sta_tx_avg_rate_sum", 0400,
- dir, srctrl, &sta_tx_avg_rate_sum_ops);
-}
-
-static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta)
-{
- struct sta_rate_control *srctrl = priv_sta;
-
- debugfs_remove(srctrl->tx_avg_rate_sum_dentry);
- debugfs_remove(srctrl->tx_avg_rate_num_dentry);
-}
-#endif
-
-static struct rate_control_ops mac80211_rcsimple = {
- .name = "simple",
- .tx_status = rate_control_simple_tx_status,
- .get_rate = rate_control_simple_get_rate,
- .rate_init = rate_control_simple_rate_init,
- .clear = rate_control_simple_clear,
- .alloc = rate_control_simple_alloc,
- .free = rate_control_simple_free,
- .alloc_sta = rate_control_simple_alloc_sta,
- .free_sta = rate_control_simple_free_sta,
-#ifdef CONFIG_MAC80211_DEBUGFS
- .add_sta_debugfs = rate_control_simple_add_sta_debugfs,
- .remove_sta_debugfs = rate_control_simple_remove_sta_debugfs,
-#endif
-};
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Simple rate control algorithm");
-
-int __init rc80211_simple_init(void)
-{
- return ieee80211_rate_control_register(&mac80211_rcsimple);
-}
-
-void rc80211_simple_exit(void)
-{
- ieee80211_rate_control_unregister(&mac80211_rcsimple);
-}
-
-#ifdef CONFIG_MAC80211_RC_SIMPLE_MODULE
-module_init(rc80211_simple_init);
-module_exit(rc80211_simple_exit);
-#endif
+++ /dev/null
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * This regulatory domain control implementation is known to be incomplete
- * and confusing. mac80211 regulatory domain control will be significantly
- * reworked in the not-too-distant future.
- *
- * For now, drivers wishing to control which channels are and aren't available
- * are advised as follows:
- * - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag
- * - continue to include *ALL* possible channels in the modes registered
- * through ieee80211_register_hwmode()
- * - for each allowable ieee80211_channel structure registered in the above
- * call, set the flag member to some meaningful value such as
- * IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
- * IEEE80211_CHAN_W_IBSS.
- * - leave flag as 0 for non-allowable channels
- *
- * The usual implementation is for a driver to read a device EEPROM to
- * determine which regulatory domain it should be operating under, then
- * looking up the allowable channels in a driver-local table, then performing
- * the above.
- */
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-
-static int ieee80211_regdom = 0x10; /* FCC */
-module_param(ieee80211_regdom, int, 0444);
-MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
-
-/*
- * If firmware is upgraded by the vendor, additional channels can be used based
- * on the new Japanese regulatory rules. This is indicated by setting
- * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
- * module.
- */
-static int ieee80211_japan_5ghz /* = 0 */;
-module_param(ieee80211_japan_5ghz, int, 0444);
-MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
-
-
-struct ieee80211_channel_range {
- short start_freq;
- short end_freq;
- unsigned char power_level;
- unsigned char antenna_max;
-};
-
-static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
- { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
- { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
- { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
- { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
- { 0 }
-};
-
-static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
- { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
- { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
- { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
- { 0 }
-};
-
-
-static const struct ieee80211_channel_range *channel_range =
- ieee80211_fcc_channels;
-
-
-static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan)
-{
- int i;
-
- chan->flag = 0;
-
- for (i = 0; channel_range[i].start_freq; i++) {
- const struct ieee80211_channel_range *r = &channel_range[i];
- if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
- if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
- chan->freq >= 5260 && chan->freq <= 5320) {
- /*
- * Skip new channels in Japan since the
- * firmware was not marked having been upgraded
- * by the vendor.
- */
- continue;
- }
-
- if (ieee80211_regdom == 0x10 &&
- (chan->freq == 5190 || chan->freq == 5210 ||
- chan->freq == 5230)) {
- /* Skip MKK channels when in FCC domain. */
- continue;
- }
-
- chan->flag |= IEEE80211_CHAN_W_SCAN |
- IEEE80211_CHAN_W_ACTIVE_SCAN |
- IEEE80211_CHAN_W_IBSS;
- chan->power_level = r->power_level;
- chan->antenna_max = r->antenna_max;
-
- if (ieee80211_regdom == 64 &&
- (chan->freq == 5170 || chan->freq == 5190 ||
- chan->freq == 5210 || chan->freq == 5230)) {
- /*
- * New regulatory rules in Japan have backwards
- * compatibility with old channels in 5.15-5.25
- * GHz band, but the station is not allowed to
- * use active scan on these old channels.
- */
- chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
- }
-
- if (ieee80211_regdom == 64 &&
- (chan->freq == 5260 || chan->freq == 5280 ||
- chan->freq == 5300 || chan->freq == 5320)) {
- /*
- * IBSS is not allowed on 5.25-5.35 GHz band
- * due to radar detection requirements.
- */
- chan->flag &= ~IEEE80211_CHAN_W_IBSS;
- }
-
- break;
- }
- }
-}
-
-
-void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode)
-{
- int c;
- for (c = 0; c < mode->num_channels; c++)
- ieee80211_unmask_channel(mode->mode, &mode->channels[c]);
-}
-
-
-void ieee80211_regdomain_init(void)
-{
- if (ieee80211_regdom == 0x40)
- channel_range = ieee80211_mkk_channels;
-}
-
* published by the Free Software Foundation.
*/
+#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include "ieee80211_i.h"
#include "ieee80211_led.h"
+#include "mesh.h"
#include "wep.h"
#include "wpa.h"
#include "tkip.h"
*/
static struct sk_buff *
ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
- struct ieee80211_rx_status *status)
+ struct ieee80211_rx_status *status,
+ struct ieee80211_rate *rate)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_rate *rate;
int needed_headroom = 0;
struct ieee80211_radiotap_header *rthdr;
__le64 *rttsft = NULL;
rtfixed->rx_flags |=
cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
- rate = ieee80211_get_rate(local, status->phymode,
- status->rate);
- if (rate)
- rtfixed->rate = rate->rate / 5;
+ rtfixed->rate = rate->bitrate / 5;
rtfixed->chan_freq = cpu_to_le16(status->freq);
- if (status->phymode == MODE_IEEE80211A)
+ if (status->band == IEEE80211_BAND_5GHZ)
rtfixed->chan_flags =
cpu_to_le16(IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_5GHZ);
if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR)
continue;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
+ continue;
+
if (prev_dev) {
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2) {
}
-/* pre-rx handlers
- *
- * these don't have dev/sdata fields in the rx data
- * The sta value should also not be used because it may
- * be NULL even though a STA (in IBSS mode) will be added.
- */
-
-static ieee80211_txrx_result
-ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
+static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
{
u8 *data = rx->skb->data;
int tid;
/* frame has qos control */
tid = qc[0] & QOS_CONTROL_TID_MASK;
if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
- rx->flags |= IEEE80211_TXRXD_RX_AMSDU;
+ rx->flags |= IEEE80211_RX_AMSDU;
else
- rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU;
+ rx->flags &= ~IEEE80211_RX_AMSDU;
} else {
if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
/* Separate TID for management frames */
if (rx->sta)
I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
- rx->u.rx.queue = tid;
+ rx->queue = tid;
/* Set skb->priority to 1d tag if highest order bit of TID is not set.
* For now, set skb->priority to 0 for other cases. */
rx->skb->priority = (tid > 7) ? 0 : tid;
-
- return TXRX_CONTINUE;
}
-
-static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
- struct sk_buff *skb,
- struct ieee80211_rx_status *status)
+static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- u32 load = 0, hdrtime;
- struct ieee80211_rate *rate;
- struct ieee80211_hw_mode *mode = local->hw.conf.mode;
- int i;
-
- /* Estimate total channel use caused by this frame */
-
- if (unlikely(mode->num_rates < 0))
- return TXRX_CONTINUE;
-
- rate = &mode->rates[0];
- for (i = 0; i < mode->num_rates; i++) {
- if (mode->rates[i].val == status->rate) {
- rate = &mode->rates[i];
- break;
- }
- }
-
- /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
- * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
- if (mode->mode == MODE_IEEE80211A ||
- (mode->mode == MODE_IEEE80211G &&
- rate->flags & IEEE80211_RATE_ERP))
- hdrtime = CHAN_UTIL_HDR_SHORT;
- else
- hdrtime = CHAN_UTIL_HDR_LONG;
-
- load = hdrtime;
- if (!is_multicast_ether_addr(hdr->addr1))
- load += hdrtime;
-
- load += skb->len * rate->rate_inv;
-
- /* Divide channel_use by 8 to avoid wrapping around the counter */
- load >>= CHAN_UTIL_SHIFT;
-
- return load;
-}
-
#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
-static ieee80211_txrx_result
-ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx)
-{
int hdrlen;
if (!WLAN_FC_DATA_PRESENT(rx->fc))
- return TXRX_CONTINUE;
+ return;
/*
* Drivers are required to align the payload data in a way that
* to move the 802.11 header further back in that case.
*/
hdrlen = ieee80211_get_hdrlen(rx->fc);
- if (rx->flags & IEEE80211_TXRXD_RX_AMSDU)
+ if (rx->flags & IEEE80211_RX_AMSDU)
hdrlen += ETH_HLEN;
WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
-
- return TXRX_CONTINUE;
-}
#endif
+}
-ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
+
+static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *status,
+ struct ieee80211_rate *rate)
{
- ieee80211_rx_h_parse_qos,
-#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
- ieee80211_rx_h_verify_ip_alignment,
-#endif
- NULL
-};
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u32 load = 0, hdrtime;
+
+ /* Estimate total channel use caused by this frame */
+
+ /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
+ * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+
+ if (status->band == IEEE80211_BAND_5GHZ ||
+ (status->band == IEEE80211_BAND_5GHZ &&
+ rate->flags & IEEE80211_RATE_ERP_G))
+ hdrtime = CHAN_UTIL_HDR_SHORT;
+ else
+ hdrtime = CHAN_UTIL_HDR_LONG;
+
+ load = hdrtime;
+ if (!is_multicast_ether_addr(hdr->addr1))
+ load += hdrtime;
+
+ /* TODO: optimise again */
+ load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
+
+ /* Divide channel_use by 8 to avoid wrapping around the counter */
+ load >>= CHAN_UTIL_SHIFT;
+
+ return load;
+}
/* rx handlers */
-static ieee80211_txrx_result
-ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx)
{
if (rx->sta)
- rx->sta->channel_use_raw += rx->u.rx.load;
- rx->sdata->channel_use_raw += rx->u.rx.load;
- return TXRX_CONTINUE;
+ rx->sta->channel_use_raw += rx->load;
+ rx->sdata->channel_use_raw += rx->load;
+ return RX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
struct sk_buff *skb = rx->skb;
if (unlikely(local->sta_hw_scanning))
- return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+ return ieee80211_sta_rx_scan(rx->dev, skb, rx->status);
if (unlikely(local->sta_sw_scanning)) {
/* drop all the other packets during a software scan anyway */
- if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
- != TXRX_QUEUED)
+ if (ieee80211_sta_rx_scan(rx->dev, skb, rx->status)
+ != RX_QUEUED)
dev_kfree_skb(skb);
- return TXRX_QUEUED;
+ return RX_QUEUED;
}
- if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) {
+ if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) {
/* scanning finished during invoking of handlers */
I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
+}
+
+static ieee80211_rx_result
+ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
+{
+ int hdrlen = ieee80211_get_hdrlen(rx->fc);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
+
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ if (!((rx->fc & IEEE80211_FCTL_FROMDS) &&
+ (rx->fc & IEEE80211_FCTL_TODS)))
+ return RX_DROP_MONITOR;
+ if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
+ return RX_DROP_MONITOR;
+ }
+
+ /* If there is not an established peer link and this is not a peer link
+ * establisment frame, beacon or probe, drop the frame.
+ */
+
+ if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) {
+ struct ieee80211_mgmt *mgmt;
+
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
+ return RX_DROP_MONITOR;
+
+ switch (rx->fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_ACTION:
+ mgmt = (struct ieee80211_mgmt *)hdr;
+ if (mgmt->u.action.category != PLINK_CATEGORY)
+ return RX_DROP_MONITOR;
+ /* fall through on else */
+ case IEEE80211_STYPE_PROBE_REQ:
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ return RX_CONTINUE;
+ break;
+ default:
+ return RX_DROP_MONITOR;
+ }
+
+ } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+ is_broadcast_ether_addr(hdr->addr1) &&
+ mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev))
+ return RX_DROP_MONITOR;
+#undef msh_h_get
+
+ return RX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
+
+static ieee80211_rx_result
+ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr;
+
hdr = (struct ieee80211_hdr *) rx->skb->data;
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&
- rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
+ rx->sta->last_seq_ctrl[rx->queue] ==
hdr->seq_ctrl)) {
- if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) {
+ if (rx->flags & IEEE80211_RX_RA_MATCH) {
rx->local->dot11FrameDuplicateCount++;
rx->sta->num_duplicates++;
}
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
} else
- rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
+ rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl;
}
if (unlikely(rx->skb->len < 16)) {
I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
}
/* Drop disallowed frame classes based on STA auth/assoc state;
* deauth/disassoc frames when needed. In addition, hostapd is
* responsible for filtering on both auth and assoc states.
*/
+
+ if (ieee80211_vif_is_mesh(&rx->sdata->vif))
+ return ieee80211_rx_mesh_check(rx);
+
if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
!(rx->fc & IEEE80211_FCTL_TODS) &&
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
- || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+ || !(rx->flags & IEEE80211_RX_RA_MATCH)) {
/* Drop IBSS frames and frames for other hosts
* silently. */
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
}
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
}
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
int keyidx;
int hdrlen;
- ieee80211_txrx_result result = TXRX_DROP;
+ ieee80211_rx_result result = RX_DROP_UNUSABLE;
struct ieee80211_key *stakey = NULL;
/*
*/
if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
/*
* No point in finding a key and decrypting if the frame is neither
* addressed to us nor a multicast frame.
*/
- if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
- return TXRX_CONTINUE;
+ if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ return RX_CONTINUE;
if (rx->sta)
stakey = rcu_dereference(rx->sta->key);
* we somehow allow the driver to tell us which key
* the hardware used if this flag is set?
*/
- if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
- (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
- return TXRX_CONTINUE;
+ if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
+ (rx->status->flag & RX_FLAG_IV_STRIPPED))
+ return RX_CONTINUE;
hdrlen = ieee80211_get_hdrlen(rx->fc);
if (rx->skb->len < 8 + hdrlen)
- return TXRX_DROP; /* TODO: count this? */
+ return RX_DROP_UNUSABLE; /* TODO: count this? */
/*
* no need to call ieee80211_wep_get_keyidx,
printk(KERN_DEBUG "%s: RX protected frame,"
" but have no key\n", rx->dev->name);
#endif /* CONFIG_MAC80211_DEBUG */
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
}
/* Check for weak IVs if possible */
if (rx->sta && rx->key->conf.alg == ALG_WEP &&
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
- (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) ||
- !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) &&
+ (!(rx->status->flag & RX_FLAG_IV_STRIPPED) ||
+ !(rx->status->flag & RX_FLAG_DECRYPTED)) &&
ieee80211_wep_is_weak_iv(rx->skb, rx->key))
rx->sta->wep_weak_iv_count++;
}
/* either the frame has been decrypted or will be dropped */
- rx->u.rx.status->flag |= RX_FLAG_DECRYPTED;
+ rx->status->flag |= RX_FLAG_DECRYPTED;
return result;
}
struct ieee80211_sub_if_data *sdata;
DECLARE_MAC_BUF(mac);
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ sdata = sta->sdata;
if (sdata->bss)
atomic_inc(&sdata->bss->num_sta_ps);
sta->flags |= WLAN_STA_PS;
- sta->pspoll = 0;
+ sta->flags &= ~WLAN_STA_PSPOLL;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
dev->name, print_mac(mac, sta->addr), sta->aid);
struct ieee80211_tx_packet_data *pkt_data;
DECLARE_MAC_BUF(mac);
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ sdata = sta->sdata;
+
if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps);
- sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM);
- sta->pspoll = 0;
- if (!skb_queue_empty(&sta->ps_tx_buf)) {
- if (local->ops->set_tim)
- local->ops->set_tim(local_to_hw(local), sta->aid, 0);
- if (sdata->bss)
- bss_tim_clear(local, sdata->bss, sta->aid);
- }
+
+ sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL);
+
+ if (!skb_queue_empty(&sta->ps_tx_buf))
+ sta_info_clear_tim_bit(sta);
+
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
dev->name, print_mac(mac, sta->addr), sta->aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+
/* Send all buffered frames to the station */
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
return sent;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
{
struct sta_info *sta = rx->sta;
struct net_device *dev = rx->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
if (!sta)
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
/* Update last_rx only for IBSS packets which are for the current
* BSSID to avoid keeping the current IBSS network alive in cases where
/* Update last_rx only for unicast frames in order to prevent
* the Probe Request frames (the only broadcast frames from a
* STA in infrastructure mode) from keeping a connection alive.
+ * Mesh beacons will update last_rx when if they are found to
+ * match the current local configuration when processed.
*/
sta->last_rx = jiffies;
}
- if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
- return TXRX_CONTINUE;
+ if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ return RX_CONTINUE;
sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
- sta->last_rssi = rx->u.rx.status->ssi;
- sta->last_signal = rx->u.rx.status->signal;
- sta->last_noise = rx->u.rx.status->noise;
+ sta->last_rssi = rx->status->ssi;
+ sta->last_signal = rx->status->signal;
+ sta->last_noise = rx->status->noise;
if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
/* Change STA power saving mode only in the end of a frame
* exchange sequence */
if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
- rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta);
+ rx->sent_ps_buffered += ap_sta_ps_end(dev, sta);
else if (!(sta->flags & WLAN_STA_PS) &&
(rx->fc & IEEE80211_FCTL_PM))
ap_sta_ps_start(dev, sta);
* as a dropped packed. */
sta->rx_packets++;
dev_kfree_skb(rx->skb);
- return TXRX_QUEUED;
+ return RX_QUEUED;
}
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
} /* ieee80211_rx_h_sta_process */
static inline struct ieee80211_fragment_entry *
compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0)
continue;
- if (entry->first_frag_time + 2 * HZ < jiffies) {
+ if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
__skb_queue_purge(&entry->skb_list);
continue;
}
return NULL;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr;
u16 sc;
if (frag == 0) {
/* This is the first fragment of a new frame. */
entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
- rx->u.rx.queue, &(rx->skb));
+ rx->queue, &(rx->skb));
if (rx->key && rx->key->conf.alg == ALG_CCMP &&
(rx->fc & IEEE80211_FCTL_PROTECTED)) {
/* Store CCMP PN so that we can verify that the next
* fragment has a sequential PN value. */
entry->ccmp = 1;
memcpy(entry->last_pn,
- rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
+ rx->key->u.ccmp.rx_pn[rx->queue],
CCMP_PN_LEN);
}
- return TXRX_QUEUED;
+ return RX_QUEUED;
}
/* This is a fragment for a frame that should already be pending in
* fragment cache. Add this fragment to the end of the pending entry.
*/
entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
- rx->u.rx.queue, hdr);
+ rx->queue, hdr);
if (!entry) {
I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
}
/* Verify that MPDUs within one MSDU have sequential PN values.
int i;
u8 pn[CCMP_PN_LEN], *rpn;
if (!rx->key || rx->key->conf.alg != ALG_CCMP)
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
memcpy(pn, entry->last_pn, CCMP_PN_LEN);
for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
pn[i]++;
if (pn[i])
break;
}
- rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue];
+ rpn = rx->key->u.ccmp.rx_pn[rx->queue];
if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
if (net_ratelimit())
printk(KERN_DEBUG "%s: defrag: CCMP PN not "
rpn[0], rpn[1], rpn[2], rpn[3], rpn[4],
rpn[5], pn[0], pn[1], pn[2], pn[3],
pn[4], pn[5]);
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
memcpy(entry->last_pn, pn, CCMP_PN_LEN);
}
entry->extra_len += rx->skb->len;
if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
rx->skb = NULL;
- return TXRX_QUEUED;
+ return RX_QUEUED;
}
rx->skb = __skb_dequeue(&entry->skb_list);
GFP_ATOMIC))) {
I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
__skb_queue_purge(&entry->skb_list);
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
}
while ((skb = __skb_dequeue(&entry->skb_list))) {
}
/* Complete frame has been reassembled - process it now */
- rx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+ rx->flags |= IEEE80211_RX_FRAGMENTED;
out:
if (rx->sta)
rx->local->dot11MulticastReceivedFrameCount++;
else
ieee80211_led_rx(rx->local);
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
struct sk_buff *skb;
if (likely(!rx->sta ||
(rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
(rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
- !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)))
- return TXRX_CONTINUE;
+ !(rx->flags & IEEE80211_RX_RA_MATCH)))
+ return RX_CONTINUE;
if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) &&
(sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
skb = skb_dequeue(&rx->sta->tx_filtered);
if (!skb) {
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *) skb->data;
- /* tell TX path to send one frame even though the STA may
- * still remain is PS mode after this frame exchange */
- rx->sta->pspoll = 1;
+ /*
+ * Tell TX path to send one frame even though the STA may
+ * still remain is PS mode after this frame exchange.
+ */
+ rx->sta->flags |= WLAN_STA_PSPOLL;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
/* Use MoreData flag to indicate whether there are more
* buffered frames for this STA */
- if (no_pending_pkts) {
+ if (no_pending_pkts)
hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
- rx->sta->flags &= ~WLAN_STA_TIM;
- } else
+ else
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
dev_queue_xmit(skb);
- if (no_pending_pkts) {
- if (rx->local->ops->set_tim)
- rx->local->ops->set_tim(local_to_hw(rx->local),
- rx->sta->aid, 0);
- if (rx->sdata->bss)
- bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid);
- }
+ if (no_pending_pkts)
+ sta_info_clear_tim_bit(rx->sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- } else if (!rx->u.rx.sent_ps_buffered) {
+ } else if (!rx->sent_ps_buffered) {
+ /*
+ * FIXME: This can be the result of a race condition between
+ * us expiring a frame and the station polling for it.
+ * Should we send it a null-func frame indicating we
+ * have nothing buffered for it?
+ */
printk(KERN_DEBUG "%s: STA %s sent PS Poll even "
"though there is no buffered frames for it\n",
rx->dev->name, print_mac(mac, rx->sta->addr));
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-
}
- /* Free PS Poll skb here instead of returning TXRX_DROP that would
+ /* Free PS Poll skb here instead of returning RX_DROP that would
* count as an dropped frame. */
dev_kfree_skb(rx->skb);
- return TXRX_QUEUED;
+ return RX_QUEUED;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
{
u16 fc = rx->fc;
u8 *data = rx->skb->data;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
if (!WLAN_FC_IS_QOS_DATA(fc))
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
/* remove the qos control field, update frame type and meta-data */
memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
hdr->frame_control = cpu_to_le16(fc);
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
static int
-ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
+ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
{
- if (unlikely(rx->sdata->ieee802_1x_pac &&
- (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)))) {
+ if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
#ifdef CONFIG_MAC80211_DEBUG
- printk(KERN_DEBUG "%s: dropped frame "
- "(unauthorized port)\n", rx->dev->name);
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: dropped frame "
+ "(unauthorized port)\n", rx->dev->name);
#endif /* CONFIG_MAC80211_DEBUG */
return -EACCES;
}
}
static int
-ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx)
+ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx)
{
/*
* Pass through unencrypted frames if the hardware has
* decrypted them already.
*/
- if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED)
+ if (rx->status->flag & RX_FLAG_DECRYPTED)
return 0;
/* Drop unencrypted frames if key is set. */
}
static int
-ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
+ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
{
struct net_device *dev = rx->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
hdrlen = ieee80211_get_hdrlen(fc);
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ int meshhdrlen = ieee80211_get_mesh_hdrlen(
+ (struct ieee80211s_hdr *) (skb->data + hdrlen));
+ /* Copy on cb:
+ * - mesh header: to be used for mesh forwarding
+ * decision. It will also be used as mesh header template at
+ * tx.c:ieee80211_subif_start_xmit() if interface
+ * type is mesh and skb->pkt_type == PACKET_OTHERHOST
+ * - ta: to be used if a RERR needs to be sent.
+ */
+ memcpy(skb->cb, skb->data + hdrlen, meshhdrlen);
+ memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN);
+ hdrlen += meshhdrlen;
+ }
+
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
* header
* IEEE 802.11 address fields:
memcpy(dst, hdr->addr3, ETH_ALEN);
memcpy(src, hdr->addr4, ETH_ALEN);
- if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) {
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
+ if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS &&
+ sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
"frame (RA=%s TA=%s DA=%s SA=%s)\n",
rx->dev->name,
print_mac(mac, hdr->addr1),
/*
* requires that rx->skb is a frame with ethernet header
*/
-static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
+static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx)
{
static const u8 pae_group_addr[ETH_ALEN]
= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
* requires that rx->skb is a frame with ethernet header
*/
static void
-ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
+ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
{
struct net_device *dev = rx->dev;
struct ieee80211_local *local = rx->local;
if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
sdata->vif.type == IEEE80211_IF_TYPE_VLAN) &&
- (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+ (rx->flags & IEEE80211_RX_RA_MATCH)) {
if (is_multicast_ether_addr(ehdr->h_dest)) {
/*
* send multicast frames both to higher layers in
"multicast frame\n", dev->name);
} else {
dsta = sta_info_get(local, skb->data);
- if (dsta && dsta->dev == dev) {
+ if (dsta && dsta->sdata->dev == dev) {
/*
* The destination station is associated to
* this AP (in this VLAN), so send the frame
xmit_skb = skb;
skb = NULL;
}
- if (dsta)
- sta_info_put(dsta);
+ }
+ }
+
+ /* Mesh forwarding */
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl;
+ (*mesh_ttl)--;
+
+ if (is_multicast_ether_addr(skb->data)) {
+ if (*mesh_ttl > 0) {
+ xmit_skb = skb_copy(skb, GFP_ATOMIC);
+ if (!xmit_skb && net_ratelimit())
+ printk(KERN_DEBUG "%s: failed to clone "
+ "multicast frame\n", dev->name);
+ else
+ xmit_skb->pkt_type = PACKET_OTHERHOST;
+ } else
+ IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
+ dropped_frames_ttl);
+ } else if (skb->pkt_type != PACKET_OTHERHOST &&
+ compare_ether_addr(dev->dev_addr, skb->data) != 0) {
+ if (*mesh_ttl == 0) {
+ IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
+ dropped_frames_ttl);
+ dev_kfree_skb(skb);
+ skb = NULL;
+ } else {
+ xmit_skb = skb;
+ xmit_skb->pkt_type = PACKET_OTHERHOST;
+ if (!(dev->flags & IFF_PROMISC))
+ skb = NULL;
+ }
}
}
}
}
-static ieee80211_txrx_result
-ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
{
struct net_device *dev = rx->dev;
struct ieee80211_local *local = rx->local;
fc = rx->fc;
if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
- if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU))
- return TXRX_CONTINUE;
+ if (!(rx->flags & IEEE80211_RX_AMSDU))
+ return RX_CONTINUE;
err = ieee80211_data_to_8023(rx);
if (unlikely(err))
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
skb->dev = dev;
/* skip the wrapping header */
eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
if (!eth)
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
while (skb != frame) {
u8 padding;
/* the last MSDU has no padding */
if (subframe_len > remaining) {
printk(KERN_DEBUG "%s: wrong buffer size", dev->name);
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
skb_pull(skb, sizeof(struct ethhdr));
subframe_len);
if (frame == NULL)
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
skb_reserve(frame, local->hw.extra_tx_headroom +
sizeof(struct ethhdr));
printk(KERN_DEBUG "%s: wrong buffer size ",
dev->name);
dev_kfree_skb(frame);
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
}
if (!ieee80211_frame_allowed(rx)) {
if (skb == frame) /* last frame */
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
dev_kfree_skb(frame);
continue;
}
ieee80211_deliver_skb(rx);
}
- return TXRX_QUEUED;
+ return RX_QUEUED;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
{
struct net_device *dev = rx->dev;
u16 fc;
fc = rx->fc;
if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
err = ieee80211_data_to_8023(rx);
if (unlikely(err))
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
if (!ieee80211_frame_allowed(rx))
- return TXRX_DROP;
+ return RX_DROP_MONITOR;
rx->skb->dev = dev;
ieee80211_deliver_skb(rx);
- return TXRX_QUEUED;
+ return RX_QUEUED;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
struct ieee80211_hw *hw = &local->hw;
u16 tid;
if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL))
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) {
if (!rx->sta)
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
tid = le16_to_cpu(bar->control) >> 12;
tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]);
if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
start_seq_num, 1);
rcu_read_unlock();
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata;
- if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
- return TXRX_DROP;
+ if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ return RX_DROP_MONITOR;
sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+ sdata->vif.type == IEEE80211_IF_TYPE_IBSS ||
+ sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) &&
!(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
- ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+ ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->status);
else
- return TXRX_DROP;
-
- return TXRX_QUEUED;
-}
-
-static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
- struct ieee80211_local *local,
- ieee80211_rx_handler *handlers,
- struct ieee80211_txrx_data *rx,
- struct sta_info *sta)
-{
- ieee80211_rx_handler *handler;
- ieee80211_txrx_result res = TXRX_DROP;
-
- for (handler = handlers; *handler != NULL; handler++) {
- res = (*handler)(rx);
-
- switch (res) {
- case TXRX_CONTINUE:
- continue;
- case TXRX_DROP:
- I802_DEBUG_INC(local->rx_handlers_drop);
- if (sta)
- sta->rx_dropped++;
- break;
- case TXRX_QUEUED:
- I802_DEBUG_INC(local->rx_handlers_queued);
- break;
- }
- break;
- }
+ return RX_DROP_MONITOR;
- if (res == TXRX_DROP)
- dev_kfree_skb(rx->skb);
- return res;
-}
-
-static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
- ieee80211_rx_handler *handlers,
- struct ieee80211_txrx_data *rx,
- struct sta_info *sta)
-{
- if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
- TXRX_CONTINUE)
- dev_kfree_skb(rx->skb);
+ return RX_QUEUED;
}
static void ieee80211_rx_michael_mic_report(struct net_device *dev,
struct ieee80211_hdr *hdr,
- struct sta_info *sta,
- struct ieee80211_txrx_data *rx)
+ struct ieee80211_rx_data *rx)
{
int keyidx, hdrlen;
DECLARE_MAC_BUF(mac);
dev->name, print_mac(mac, hdr->addr2),
print_mac(mac2, hdr->addr1), keyidx);
- if (!sta) {
+ if (!rx->sta) {
/*
* Some hardware seem to generate incorrect Michael MIC
* reports; ignore them to avoid triggering countermeasures.
rx->skb = NULL;
}
-ieee80211_rx_handler ieee80211_rx_handlers[] =
+/* TODO: use IEEE80211_RX_FRAGMENTED */
+static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_local *local = rx->local;
+ struct ieee80211_rtap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 flags;
+ u8 rate;
+ __le16 chan_freq;
+ __le16 chan_flags;
+ } __attribute__ ((packed)) *rthdr;
+ struct sk_buff *skb = rx->skb, *skb2;
+ struct net_device *prev_dev = NULL;
+ struct ieee80211_rx_status *status = rx->status;
+
+ if (rx->flags & IEEE80211_RX_CMNTR_REPORTED)
+ goto out_free_skb;
+
+ if (skb_headroom(skb) < sizeof(*rthdr) &&
+ pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
+ goto out_free_skb;
+
+ rthdr = (void *)skb_push(skb, sizeof(*rthdr));
+ memset(rthdr, 0, sizeof(*rthdr));
+ rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+ rthdr->hdr.it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL));
+
+ rthdr->rate = rx->rate->bitrate / 5;
+ rthdr->chan_freq = cpu_to_le16(status->freq);
+
+ if (status->band == IEEE80211_BAND_5GHZ)
+ rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_5GHZ);
+ else
+ rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN |
+ IEEE80211_CHAN_2GHZ);
+
+ skb_set_mac_header(skb, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (!netif_running(sdata->dev))
+ continue;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR ||
+ !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+ continue;
+
+ if (prev_dev) {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+ skb2->dev = prev_dev;
+ netif_rx(skb2);
+ }
+ }
+
+ prev_dev = sdata->dev;
+ sdata->dev->stats.rx_packets++;
+ sdata->dev->stats.rx_bytes += skb->len;
+ }
+
+ if (prev_dev) {
+ skb->dev = prev_dev;
+ netif_rx(skb);
+ skb = NULL;
+ } else
+ goto out_free_skb;
+
+ rx->flags |= IEEE80211_RX_CMNTR_REPORTED;
+ return;
+
+ out_free_skb:
+ dev_kfree_skb(skb);
+}
+
+typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *);
+static ieee80211_rx_handler ieee80211_rx_handlers[] =
{
ieee80211_rx_h_if_stats,
ieee80211_rx_h_passive_scan,
NULL
};
+static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_rx_data *rx,
+ struct sk_buff *skb)
+{
+ ieee80211_rx_handler *handler;
+ ieee80211_rx_result res = RX_DROP_MONITOR;
+
+ rx->skb = skb;
+ rx->sdata = sdata;
+ rx->dev = sdata->dev;
+
+ for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) {
+ res = (*handler)(rx);
+
+ switch (res) {
+ case RX_CONTINUE:
+ continue;
+ case RX_DROP_UNUSABLE:
+ case RX_DROP_MONITOR:
+ I802_DEBUG_INC(sdata->local->rx_handlers_drop);
+ if (rx->sta)
+ rx->sta->rx_dropped++;
+ break;
+ case RX_QUEUED:
+ I802_DEBUG_INC(sdata->local->rx_handlers_queued);
+ break;
+ }
+ break;
+ }
+
+ switch (res) {
+ case RX_CONTINUE:
+ case RX_DROP_MONITOR:
+ ieee80211_rx_cooked_monitor(rx);
+ break;
+ case RX_DROP_UNUSABLE:
+ dev_kfree_skb(rx->skb);
+ break;
+ }
+}
+
/* main receive path */
static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
- u8 *bssid, struct ieee80211_txrx_data *rx,
+ u8 *bssid, struct ieee80211_rx_data *rx,
struct ieee80211_hdr *hdr)
{
int multicast = is_multicast_ether_addr(hdr->addr1);
if (!bssid)
return 0;
if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
- if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+ if (!(rx->flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!multicast &&
compare_ether_addr(sdata->dev->dev_addr,
hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
case IEEE80211_IF_TYPE_IBSS:
if (!bssid)
return 0;
- if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
- if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
+ (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
+ return 1;
+ else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+ if (!(rx->flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!multicast &&
compare_ether_addr(sdata->dev->dev_addr,
hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!rx->sta)
rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb,
bssid, hdr->addr2);
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ if (!multicast &&
+ compare_ether_addr(sdata->dev->dev_addr,
+ hdr->addr1) != 0) {
+ if (!(sdata->dev->flags & IFF_PROMISC))
+ return 0;
+
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ }
+ break;
case IEEE80211_IF_TYPE_VLAN:
case IEEE80211_IF_TYPE_AP:
if (!bssid) {
return 0;
} else if (!ieee80211_bssid_match(bssid,
sdata->dev->dev_addr)) {
- if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+ if (!(rx->flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
if (sdata->dev == sdata->local->mdev &&
- !(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+ !(rx->flags & IEEE80211_RX_IN_SCAN))
/* do not receive anything via
* master device when not scanning */
return 0;
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_rx_status *status,
- u32 load)
+ u32 load,
+ struct ieee80211_rate *rate)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
- struct sta_info *sta;
struct ieee80211_hdr *hdr;
- struct ieee80211_txrx_data rx;
+ struct ieee80211_rx_data rx;
u16 type;
int prepares;
struct ieee80211_sub_if_data *prev = NULL;
rx.skb = skb;
rx.local = local;
- rx.u.rx.status = status;
- rx.u.rx.load = load;
+ rx.status = status;
+ rx.load = load;
+ rx.rate = rate;
rx.fc = le16_to_cpu(hdr->frame_control);
type = rx.fc & IEEE80211_FCTL_FTYPE;
if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
local->dot11ReceivedFragmentCount++;
- sta = rx.sta = sta_info_get(local, hdr->addr2);
- if (sta) {
- rx.dev = rx.sta->dev;
- rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
+ rx.sta = sta_info_get(local, hdr->addr2);
+ if (rx.sta) {
+ rx.sdata = rx.sta->sdata;
+ rx.dev = rx.sta->sdata->dev;
}
if ((status->flag & RX_FLAG_MMIC_ERROR)) {
- ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
- goto end;
+ ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
+ return;
}
if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
- rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
+ rx.flags |= IEEE80211_RX_IN_SCAN;
- if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
- sta) != TXRX_CONTINUE)
- goto end;
- skb = rx.skb;
+ ieee80211_parse_qos(&rx);
+ ieee80211_verify_ip_alignment(&rx);
- if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) &&
- !atomic_read(&local->iff_promiscs) &&
- !is_multicast_ether_addr(hdr->addr1)) {
- rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
- ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
- rx.sta);
- sta_info_put(sta);
- return;
- }
+ skb = rx.skb;
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
- rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
+ rx.flags |= IEEE80211_RX_RA_MATCH;
prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
- /* prepare_for_handlers can change sta */
- sta = rx.sta;
if (!prepares)
continue;
continue;
}
rx.fc = le16_to_cpu(hdr->frame_control);
- rx.skb = skb_new;
- rx.dev = prev->dev;
- rx.sdata = prev;
- ieee80211_invoke_rx_handlers(local, local->rx_handlers,
- &rx, sta);
+ ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
prev = sdata;
}
if (prev) {
rx.fc = le16_to_cpu(hdr->frame_control);
- rx.skb = skb;
- rx.dev = prev->dev;
- rx.sdata = prev;
- ieee80211_invoke_rx_handlers(local, local->rx_handlers,
- &rx, sta);
+ ieee80211_invoke_rx_handlers(prev, &rx, skb);
} else
dev_kfree_skb(skb);
-
- end:
- if (sta)
- sta_info_put(sta);
}
#define SEQ_MODULO 0x1000
u16 head_seq_num, buf_size;
int index;
u32 pkt_load;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *rate;
buf_size = tid_agg_rx->buf_size;
head_seq_num = tid_agg_rx->head_seq_num;
memcpy(&status,
tid_agg_rx->reorder_buf[index]->cb,
sizeof(status));
+ sband = local->hw.wiphy->bands[status.band];
+ rate = &sband->bitrates[status.rate_idx];
pkt_load = ieee80211_rx_load_stats(local,
tid_agg_rx->reorder_buf[index],
- &status);
+ &status, rate);
__ieee80211_rx_handle_packet(hw,
tid_agg_rx->reorder_buf[index],
- &status, pkt_load);
+ &status, pkt_load, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
}
/* release the reordered frame back to stack */
memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
sizeof(status));
+ sband = local->hw.wiphy->bands[status.band];
+ rate = &sband->bitrates[status.rate_idx];
pkt_load = ieee80211_rx_load_stats(local,
tid_agg_rx->reorder_buf[index],
- &status);
+ &status, rate);
__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
- &status, pkt_load);
+ &status, pkt_load, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
if (sc & IEEE80211_SCTL_FRAG) {
- ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
+ ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
ret = 1;
goto end_reorder;
mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
mpdu_seq_num, 0);
-end_reorder:
- if (sta)
- sta_info_put(sta);
+ end_reorder:
return ret;
}
{
struct ieee80211_local *local = hw_to_local(hw);
u32 pkt_load;
+ struct ieee80211_rate *rate = NULL;
+ struct ieee80211_supported_band *sband;
+
+ if (status->band < 0 ||
+ status->band > IEEE80211_NUM_BANDS) {
+ WARN_ON(1);
+ return;
+ }
+
+ sband = local->hw.wiphy->bands[status->band];
+
+ if (!sband ||
+ status->rate_idx < 0 ||
+ status->rate_idx >= sband->n_bitrates) {
+ WARN_ON(1);
+ return;
+ }
+
+ rate = &sband->bitrates[status->rate_idx];
/*
* key references and virtual interfaces are protected using RCU
* if it was previously present.
* Also, frames with less than 16 bytes are dropped.
*/
- skb = ieee80211_rx_monitor(local, skb, status);
+ skb = ieee80211_rx_monitor(local, skb, status, rate);
if (!skb) {
rcu_read_unlock();
return;
}
- pkt_load = ieee80211_rx_load_stats(local, skb, status);
+ pkt_load = ieee80211_rx_load_stats(local, skb, status, rate);
local->channel_use_raw += pkt_load;
if (!ieee80211_rx_reorder_ampdu(local, skb))
- __ieee80211_rx_handle_packet(hw, skb, status, pkt_load);
+ __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate);
rcu_read_unlock();
}
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/timer.h>
+#include <linux/rtnetlink.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
#include "sta_info.h"
#include "debugfs_sta.h"
+#include "mesh.h"
-/* Caller must hold local->sta_lock */
-static void sta_info_hash_add(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
- local->sta_hash[STA_HASH(sta->addr)] = sta;
-}
-
+/**
+ * DOC: STA information lifetime rules
+ *
+ * STA info structures (&struct sta_info) are managed in a hash table
+ * for faster lookup and a list for iteration. They are managed using
+ * RCU, i.e. access to the list and hash table is protected by RCU.
+ *
+ * Upon allocating a STA info structure with sta_info_alloc(), the caller owns
+ * that structure. It must then either destroy it using sta_info_destroy()
+ * (which is pretty useless) or insert it into the hash table using
+ * sta_info_insert() which demotes the reference from ownership to a regular
+ * RCU-protected reference; if the function is called without protection by an
+ * RCU critical section the reference is instantly invalidated.
+ *
+ * Because there are debugfs entries for each station, and adding those
+ * must be able to sleep, it is also possible to "pin" a station entry,
+ * that means it can be removed from the hash table but not be freed.
+ * See the comment in __sta_info_unlink() for more information.
+ *
+ * In order to remove a STA info structure, the caller needs to first
+ * unlink it (sta_info_unlink()) from the list and hash tables and
+ * then wait for an RCU synchronisation before it can be freed. Due to
+ * the pinning and the possibility of multiple callers trying to remove
+ * the same STA info at the same time, sta_info_unlink() can clear the
+ * STA info pointer it is passed to indicate that the STA info is owned
+ * by somebody else now.
+ *
+ * If sta_info_unlink() did not clear the pointer then the caller owns
+ * the STA info structure now and is responsible of destroying it with
+ * a call to sta_info_destroy(), not before RCU synchronisation, of
+ * course. Note that sta_info_destroy() must be protected by the RTNL.
+ *
+ * In all other cases, there is no concept of ownership on a STA entry,
+ * each structure is owned by the global hash table/list until it is
+ * removed. All users of the structure need to be RCU protected so that
+ * the structure won't be freed before they are done using it.
+ */
/* Caller must hold local->sta_lock */
static int sta_info_hash_del(struct ieee80211_local *local,
if (!s)
return -ENOENT;
if (s == sta) {
- local->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+ rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)],
+ s->hnext);
return 0;
}
while (s->hnext && s->hnext != sta)
s = s->hnext;
if (s->hnext) {
- s->hnext = sta->hnext;
+ rcu_assign_pointer(s->hnext, sta->hnext);
return 0;
}
return -ENOENT;
}
-struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
+/* protected by RCU */
+static struct sta_info *__sta_info_find(struct ieee80211_local *local,
+ u8 *addr)
{
struct sta_info *sta;
- read_lock_bh(&local->sta_lock);
- sta = local->sta_hash[STA_HASH(addr)];
+ sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
while (sta) {
- if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
- __sta_info_get(sta);
+ if (compare_ether_addr(sta->addr, addr) == 0)
break;
- }
- sta = sta->hnext;
+ sta = rcu_dereference(sta->hnext);
}
- read_unlock_bh(&local->sta_lock);
-
return sta;
}
+
+struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
+{
+ return __sta_info_find(local, addr);
+}
EXPORT_SYMBOL(sta_info_get);
-int sta_info_min_txrate_get(struct ieee80211_local *local)
+struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
+ struct net_device *dev)
{
struct sta_info *sta;
- struct ieee80211_hw_mode *mode;
- int min_txrate = 9999999;
- int i;
-
- read_lock_bh(&local->sta_lock);
- mode = local->oper_hw_mode;
- for (i = 0; i < STA_HASH_SIZE; i++) {
- sta = local->sta_hash[i];
- while (sta) {
- if (sta->txrate < min_txrate)
- min_txrate = sta->txrate;
- sta = sta->hnext;
+ int i = 0;
+
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (dev && dev != sta->sdata->dev)
+ continue;
+ if (i < idx) {
+ ++i;
+ continue;
}
+ return sta;
}
- read_unlock_bh(&local->sta_lock);
- if (min_txrate == 9999999)
- min_txrate = 0;
- return mode->rates[min_txrate].rate;
+ return NULL;
}
-
-static void sta_info_release(struct kref *kref)
+void sta_info_destroy(struct sta_info *sta)
{
- struct sta_info *sta = container_of(kref, struct sta_info, kref);
struct ieee80211_local *local = sta->local;
struct sk_buff *skb;
int i;
+ DECLARE_MAC_BUF(mbuf);
+
+ if (!sta)
+ return;
+
+ ASSERT_RTNL();
+ might_sleep();
+
+ rate_control_remove_sta_debugfs(sta);
+ ieee80211_sta_debugfs_remove(sta);
+
+#ifdef CONFIG_MAC80211_MESH
+ if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+ mesh_plink_deactivate(sta);
+#endif
+
+ /*
+ * NOTE: This will call synchronize_rcu() internally to
+ * make sure no key references can be in use. We rely on
+ * that here for the mesh code!
+ */
+ ieee80211_key_free(sta->key);
+ WARN_ON(sta->key);
+
+#ifdef CONFIG_MAC80211_MESH
+ if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+ del_timer_sync(&sta->plink_timer);
+#endif
- /* free sta structure; it has already been removed from
- * hash table etc. external structures. Make sure that all
- * buffered frames are release (one might have been added
- * after sta_info_free() was called). */
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
local->total_ps_buffered--;
dev_kfree_skb_any(skb);
}
- while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+
+ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
dev_kfree_skb_any(skb);
- }
- for (i = 0; i < STA_TID_NUM; i++)
+
+ for (i = 0; i < STA_TID_NUM; i++) {
del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer);
+ del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
+ }
rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
rate_control_put(sta->rate_ctrl);
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Destroyed STA %s\n",
+ wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
kfree(sta);
}
-void sta_info_put(struct sta_info *sta)
+/* Caller must hold local->sta_lock */
+static void sta_info_hash_add(struct ieee80211_local *local,
+ struct sta_info *sta)
{
- kref_put(&sta->kref, sta_info_release);
+ sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
+ rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta);
}
-EXPORT_SYMBOL(sta_info_put);
-
-struct sta_info * sta_info_add(struct ieee80211_local *local,
- struct net_device *dev, u8 *addr, gfp_t gfp)
+struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
+ u8 *addr, gfp_t gfp)
{
+ struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
int i;
- DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mbuf);
sta = kzalloc(sizeof(*sta), gfp);
if (!sta)
return NULL;
- kref_init(&sta->kref);
+ memcpy(sta->addr, addr, ETH_ALEN);
+ sta->local = local;
+ sta->sdata = sdata;
sta->rate_ctrl = rate_control_get(local->rate_ctrl);
- sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
+ sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
+ gfp);
if (!sta->rate_ctrl_priv) {
rate_control_put(sta->rate_ctrl);
kfree(sta);
return NULL;
}
- memcpy(sta->addr, addr, ETH_ALEN);
- sta->local = local;
- sta->dev = dev;
spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
for (i = 0; i < STA_TID_NUM; i++) {
/* timer_to_tid must be initialized with identity mapping to
* enable session_timer's data differentiation. refer to
* sta_rx_agg_session_timer_expired for useage */
sta->timer_to_tid[i] = i;
+ /* tid to tx queue: initialize according to HW (0 is valid) */
+ sta->tid_to_tx_q[i] = local->hw.queues;
/* rx timers */
sta->ampdu_mlme.tid_rx[i].session_timer.function =
sta_rx_agg_session_timer_expired;
sta->ampdu_mlme.tid_rx[i].session_timer.data =
(unsigned long)&sta->timer_to_tid[i];
init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer);
+ /* tx timers */
+ sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function =
+ sta_addba_resp_timer_expired;
+ sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data =
+ (unsigned long)&sta->timer_to_tid[i];
+ init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
}
skb_queue_head_init(&sta->ps_tx_buf);
skb_queue_head_init(&sta->tx_filtered);
- __sta_info_get(sta); /* sta used by caller, decremented by
- * sta_info_put() */
- write_lock_bh(&local->sta_lock);
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Allocated STA %s\n",
+ wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+#ifdef CONFIG_MAC80211_MESH
+ sta->plink_state = PLINK_LISTEN;
+ spin_lock_init(&sta->plink_lock);
+ init_timer(&sta->plink_timer);
+#endif
+
+ return sta;
+}
+
+int sta_info_insert(struct sta_info *sta)
+{
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ /*
+ * Can't be a WARN_ON because it can be triggered through a race:
+ * something inserts a STA (on one CPU) without holding the RTNL
+ * and another CPU turns off the net device.
+ */
+ if (unlikely(!netif_running(sdata->dev)))
+ return -ENETDOWN;
+
+ if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0))
+ return -EINVAL;
+
+ if (WARN_ON(is_multicast_ether_addr(sta->addr)))
+ return -EINVAL;
+
+ spin_lock_irqsave(&local->sta_lock, flags);
+ /* check if STA exists already */
+ if (__sta_info_find(local, sta->addr)) {
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+ return -EEXIST;
+ }
list_add(&sta->list, &local->sta_list);
local->num_sta++;
sta_info_hash_add(local, sta);
- if (local->ops->sta_notify) {
- struct ieee80211_sub_if_data *sdata;
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ /* notify driver */
+ if (local->ops->sta_notify) {
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
sdata = sdata->u.vlan.ap;
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
- STA_NOTIFY_ADD, addr);
+ STA_NOTIFY_ADD, sta->addr);
}
- write_unlock_bh(&local->sta_lock);
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Added STA %s\n",
- wiphy_name(local->hw.wiphy), print_mac(mac, addr));
+ printk(KERN_DEBUG "%s: Inserted STA %s\n",
+ wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+
#ifdef CONFIG_MAC80211_DEBUGFS
/* debugfs entry adding might sleep, so schedule process
* context task for adding entry for STAs that do not yet
queue_work(local->hw.workqueue, &local->sta_debugfs_add);
#endif
- return sta;
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_accept_plinks_update(sdata);
+
+ return 0;
}
-/* Caller must hold local->sta_lock */
-void sta_info_remove(struct sta_info *sta)
+static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
{
- struct ieee80211_local *local = sta->local;
- struct ieee80211_sub_if_data *sdata;
+ /*
+ * This format has been mandated by the IEEE specifications,
+ * so this line may not be changed to use the __set_bit() format.
+ */
+ bss->tim[aid / 8] |= (1 << (aid % 8));
+}
- /* don't do anything if we've been removed already */
- if (sta_info_hash_del(local, sta))
- return;
+static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
+{
+ /*
+ * This format has been mandated by the IEEE specifications,
+ * so this line may not be changed to use the __clear_bit() format.
+ */
+ bss->tim[aid / 8] &= ~(1 << (aid % 8));
+}
- list_del(&sta->list);
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
- if (sta->flags & WLAN_STA_PS) {
- sta->flags &= ~WLAN_STA_PS;
- if (sdata->bss)
- atomic_dec(&sdata->bss->num_sta_ps);
+static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
+ struct sta_info *sta)
+{
+ if (bss)
+ __bss_tim_set(bss, sta->aid);
+ if (sta->local->ops->set_tim) {
+ sta->local->tim_in_locked_section = true;
+ sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
+ sta->local->tim_in_locked_section = false;
}
- local->num_sta--;
- sta_info_remove_aid_ptr(sta);
+}
+
+void sta_info_set_tim_bit(struct sta_info *sta)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&sta->local->sta_lock, flags);
+ __sta_info_set_tim_bit(sta->sdata->bss, sta);
+ spin_unlock_irqrestore(&sta->local->sta_lock, flags);
}
-void sta_info_free(struct sta_info *sta)
+static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
+ struct sta_info *sta)
{
- struct sk_buff *skb;
- struct ieee80211_local *local = sta->local;
- DECLARE_MAC_BUF(mac);
+ if (bss)
+ __bss_tim_clear(bss, sta->aid);
+ if (sta->local->ops->set_tim) {
+ sta->local->tim_in_locked_section = true;
+ sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
+ sta->local->tim_in_locked_section = false;
+ }
+}
- might_sleep();
+void sta_info_clear_tim_bit(struct sta_info *sta)
+{
+ unsigned long flags;
- write_lock_bh(&local->sta_lock);
- sta_info_remove(sta);
- write_unlock_bh(&local->sta_lock);
+ spin_lock_irqsave(&sta->local->sta_lock, flags);
+ __sta_info_clear_tim_bit(sta->sdata->bss, sta);
+ spin_unlock_irqrestore(&sta->local->sta_lock, flags);
+}
- while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
- local->total_ps_buffered--;
- dev_kfree_skb(skb);
- }
- while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
- dev_kfree_skb(skb);
- }
+/*
+ * See comment in __sta_info_unlink,
+ * caller must hold local->sta_lock.
+ */
+static void __sta_info_pin(struct sta_info *sta)
+{
+ WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL);
+ sta->pin_status = STA_INFO_PIN_STAT_PINNED;
+}
+
+/*
+ * See comment in __sta_info_unlink, returns sta if it
+ * needs to be destroyed.
+ */
+static struct sta_info *__sta_info_unpin(struct sta_info *sta)
+{
+ struct sta_info *ret = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&sta->local->sta_lock, flags);
+ WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY &&
+ sta->pin_status != STA_INFO_PIN_STAT_PINNED);
+ if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY)
+ ret = sta;
+ sta->pin_status = STA_INFO_PIN_STAT_NORMAL;
+ spin_unlock_irqrestore(&sta->local->sta_lock, flags);
+
+ return ret;
+}
+
+static void __sta_info_unlink(struct sta_info **sta)
+{
+ struct ieee80211_local *local = (*sta)->local;
+ struct ieee80211_sub_if_data *sdata = (*sta)->sdata;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Removed STA %s\n",
- wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ DECLARE_MAC_BUF(mbuf);
+#endif
+ /*
+ * pull caller's reference if we're already gone.
+ */
+ if (sta_info_hash_del(local, *sta)) {
+ *sta = NULL;
+ return;
+ }
- ieee80211_key_free(sta->key);
- sta->key = NULL;
+ /*
+ * Also pull caller's reference if the STA is pinned by the
+ * task that is adding the debugfs entries. In that case, we
+ * leave the STA "to be freed".
+ *
+ * The rules are not trivial, but not too complex either:
+ * (1) pin_status is only modified under the sta_lock
+ * (2) sta_info_debugfs_add_work() will set the status
+ * to PINNED when it found an item that needs a new
+ * debugfs directory created. In that case, that item
+ * must not be freed although all *RCU* users are done
+ * with it. Hence, we tell the caller of _unlink()
+ * that the item is already gone (as can happen when
+ * two tasks try to unlink/destroy at the same time)
+ * (3) We set the pin_status to DESTROY here when we
+ * find such an item.
+ * (4) sta_info_debugfs_add_work() will reset the pin_status
+ * from PINNED to NORMAL when it is done with the item,
+ * but will check for DESTROY before resetting it in
+ * which case it will free the item.
+ */
+ if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) {
+ (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY;
+ *sta = NULL;
+ return;
+ }
- if (local->ops->sta_notify) {
- struct ieee80211_sub_if_data *sdata;
+ list_del(&(*sta)->list);
+
+ if ((*sta)->flags & WLAN_STA_PS) {
+ (*sta)->flags &= ~WLAN_STA_PS;
+ if (sdata->bss)
+ atomic_dec(&sdata->bss->num_sta_ps);
+ __sta_info_clear_tim_bit(sdata->bss, *sta);
+ }
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ local->num_sta--;
+ if (local->ops->sta_notify) {
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
sdata = sdata->u.vlan.ap;
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
- STA_NOTIFY_REMOVE, sta->addr);
+ STA_NOTIFY_REMOVE, (*sta)->addr);
}
- rate_control_remove_sta_debugfs(sta);
- ieee80211_sta_debugfs_remove(sta);
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ mesh_accept_plinks_update(sdata);
+#ifdef CONFIG_MAC80211_MESH
+ del_timer(&(*sta)->plink_timer);
+#endif
+ }
- sta_info_put(sta);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Removed STA %s\n",
+ wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
}
+void sta_info_unlink(struct sta_info **sta)
+{
+ struct ieee80211_local *local = (*sta)->local;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->sta_lock, flags);
+ __sta_info_unlink(sta);
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+}
static inline int sta_info_buffer_expired(struct ieee80211_local *local,
struct sta_info *sta,
{
unsigned long flags;
struct sk_buff *skb;
+ struct ieee80211_sub_if_data *sdata;
DECLARE_MAC_BUF(mac);
if (skb_queue_empty(&sta->ps_tx_buf))
for (;;) {
spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
skb = skb_peek(&sta->ps_tx_buf);
- if (sta_info_buffer_expired(local, sta, skb)) {
+ if (sta_info_buffer_expired(local, sta, skb))
skb = __skb_dequeue(&sta->ps_tx_buf);
- if (skb_queue_empty(&sta->ps_tx_buf))
- sta->flags &= ~WLAN_STA_TIM;
- } else
+ else
skb = NULL;
spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
- if (skb) {
- local->total_ps_buffered--;
- printk(KERN_DEBUG "Buffered frame expired (STA "
- "%s)\n", print_mac(mac, sta->addr));
- dev_kfree_skb(skb);
- } else
+ if (!skb)
break;
+
+ sdata = sta->sdata;
+ local->total_ps_buffered--;
+ printk(KERN_DEBUG "Buffered frame expired (STA "
+ "%s)\n", print_mac(mac, sta->addr));
+ dev_kfree_skb(skb);
+
+ if (skb_queue_empty(&sta->ps_tx_buf))
+ sta_info_clear_tim_bit(sta);
}
}
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sta_info *sta;
- read_lock_bh(&local->sta_lock);
- list_for_each_entry(sta, &local->sta_list, list) {
- __sta_info_get(sta);
+ rcu_read_lock();
+ list_for_each_entry_rcu(sta, &local->sta_list, list)
sta_info_cleanup_expire_buffered(local, sta);
- sta_info_put(sta);
- }
- read_unlock_bh(&local->sta_lock);
+ rcu_read_unlock();
local->sta_cleanup.expires =
round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
}
#ifdef CONFIG_MAC80211_DEBUGFS
-static void sta_info_debugfs_add_task(struct work_struct *work)
+static void sta_info_debugfs_add_work(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, sta_debugfs_add);
struct sta_info *sta, *tmp;
+ unsigned long flags;
while (1) {
sta = NULL;
- read_lock_bh(&local->sta_lock);
+
+ spin_lock_irqsave(&local->sta_lock, flags);
list_for_each_entry(tmp, &local->sta_list, list) {
if (!tmp->debugfs.dir) {
sta = tmp;
- __sta_info_get(sta);
+ __sta_info_pin(sta);
break;
}
}
- read_unlock_bh(&local->sta_lock);
+ spin_unlock_irqrestore(&local->sta_lock, flags);
if (!sta)
break;
ieee80211_sta_debugfs_add(sta);
rate_control_add_sta_debugfs(sta);
- sta_info_put(sta);
+
+ sta = __sta_info_unpin(sta);
+
+ if (sta) {
+ synchronize_rcu();
+ sta_info_destroy(sta);
+ }
}
}
#endif
void sta_info_init(struct ieee80211_local *local)
{
- rwlock_init(&local->sta_lock);
+ spin_lock_init(&local->sta_lock);
INIT_LIST_HEAD(&local->sta_list);
setup_timer(&local->sta_cleanup, sta_info_cleanup,
round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
#ifdef CONFIG_MAC80211_DEBUGFS
- INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task);
+ INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work);
#endif
}
sta_info_flush(local, NULL);
}
-void sta_info_remove_aid_ptr(struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata;
-
- if (sta->aid <= 0)
- return;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-
- if (sdata->local->ops->set_tim)
- sdata->local->ops->set_tim(local_to_hw(sdata->local),
- sta->aid, 0);
- if (sdata->bss)
- __bss_tim_clear(sdata->bss, sta->aid);
-}
-
-
/**
* sta_info_flush - flush matching STA entries from the STA table
+ *
+ * Returns the number of removed STA entries.
+ *
* @local: local interface data
- * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs
+ * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs
*/
-void sta_info_flush(struct ieee80211_local *local, struct net_device *dev)
+int sta_info_flush(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
{
struct sta_info *sta, *tmp;
LIST_HEAD(tmp_list);
+ int ret = 0;
+ unsigned long flags;
- write_lock_bh(&local->sta_lock);
- list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
- if (!dev || dev == sta->dev) {
- __sta_info_get(sta);
- sta_info_remove(sta);
- list_add_tail(&sta->list, &tmp_list);
- }
- write_unlock_bh(&local->sta_lock);
+ might_sleep();
- list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
- sta_info_free(sta);
- sta_info_put(sta);
+ spin_lock_irqsave(&local->sta_lock, flags);
+ list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
+ if (!sdata || sdata == sta->sdata) {
+ __sta_info_unlink(&sta);
+ if (sta) {
+ list_add_tail(&sta->list, &tmp_list);
+ ret++;
+ }
+ }
}
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+
+ synchronize_rcu();
+
+ list_for_each_entry_safe(sta, tmp, &tmp_list, list)
+ sta_info_destroy(sta);
+
+ return ret;
}
#include <linux/list.h>
#include <linux/types.h>
#include <linux/if_ether.h>
-#include <linux/kref.h>
#include "ieee80211_key.h"
-/* Stations flags (struct sta_info::flags) */
-#define WLAN_STA_AUTH BIT(0)
-#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
-#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
-#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
- * controlling whether STA is authorized to
- * send and receive non-IEEE 802.1X frames
- */
-#define WLAN_STA_SHORT_PREAMBLE BIT(7)
-/* whether this is an AP that we are associated with as a client */
-#define WLAN_STA_ASSOC_AP BIT(8)
-#define WLAN_STA_WME BIT(9)
-#define WLAN_STA_WDS BIT(27)
+/**
+ * enum ieee80211_sta_info_flags - Stations flags
+ *
+ * These flags are used with &struct sta_info's @flags member.
+ *
+ * @WLAN_STA_AUTH: Station is authenticated.
+ * @WLAN_STA_ASSOC: Station is associated.
+ * @WLAN_STA_PS: Station is in power-save mode
+ * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic.
+ * This bit is always checked so needs to be enabled for all stations
+ * when virtual port control is not in use.
+ * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
+ * frames.
+ * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
+ * @WLAN_STA_WME: Station is a QoS-STA.
+ * @WLAN_STA_WDS: Station is one of our WDS peers.
+ * @WLAN_STA_PSPOLL: Station has just PS-polled us.
+ * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
+ * IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next
+ * frame to this station is transmitted.
+ */
+enum ieee80211_sta_info_flags {
+ WLAN_STA_AUTH = 1<<0,
+ WLAN_STA_ASSOC = 1<<1,
+ WLAN_STA_PS = 1<<2,
+ WLAN_STA_AUTHORIZED = 1<<3,
+ WLAN_STA_SHORT_PREAMBLE = 1<<4,
+ WLAN_STA_ASSOC_AP = 1<<5,
+ WLAN_STA_WME = 1<<6,
+ WLAN_STA_WDS = 1<<7,
+ WLAN_STA_PSPOLL = 1<<8,
+ WLAN_STA_CLEAR_PS_FILT = 1<<9,
+};
#define STA_TID_NUM 16
#define ADDBA_RESP_INTERVAL HZ
+#define HT_AGG_MAX_RETRIES (0x3)
#define HT_AGG_STATE_INITIATOR_SHIFT (4)
+#define HT_ADDBA_REQUESTED_MSK BIT(0)
+#define HT_ADDBA_DRV_READY_MSK BIT(1)
+#define HT_ADDBA_RECEIVED_MSK BIT(2)
#define HT_AGG_STATE_REQ_STOP_BA_MSK BIT(3)
-
+#define HT_AGG_STATE_INITIATOR_MSK BIT(HT_AGG_STATE_INITIATOR_SHIFT)
#define HT_AGG_STATE_IDLE (0x0)
-#define HT_AGG_STATE_OPERATIONAL (0x7)
+#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \
+ HT_ADDBA_DRV_READY_MSK | \
+ HT_ADDBA_RECEIVED_MSK)
+
+/**
+ * struct tid_ampdu_tx - TID aggregation information (Tx).
+ *
+ * @state: TID's state in session state machine.
+ * @dialog_token: dialog token for aggregation session
+ * @ssn: Starting Sequence Number expected to be aggregated.
+ * @addba_resp_timer: timer for peer's response to addba request
+ * @addba_req_num: number of times addBA request has been sent.
+ */
+struct tid_ampdu_tx {
+ u8 state;
+ u8 dialog_token;
+ u16 ssn;
+ struct timer_list addba_resp_timer;
+ u8 addba_req_num;
+};
/**
* struct tid_ampdu_rx - TID aggregation information (Rx).
};
/**
+ * enum plink_state - state of a mesh peer link finite state machine
+ *
+ * @PLINK_LISTEN: initial state, considered the implicit state of non existant
+ * mesh peer links
+ * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer
+ * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer
+ * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh
+ * peer
+ * @PLINK_ESTAB: mesh peer link is established
+ * @PLINK_HOLDING: mesh peer link is being closed or cancelled
+ * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded
+ */
+enum plink_state {
+ PLINK_LISTEN,
+ PLINK_OPN_SNT,
+ PLINK_OPN_RCVD,
+ PLINK_CNF_RCVD,
+ PLINK_ESTAB,
+ PLINK_HOLDING,
+ PLINK_BLOCKED
+};
+
+/**
* struct sta_ampdu_mlme - STA aggregation information.
*
- * @tid_agg_info_rx: aggregation info for Rx per TID
+ * @tid_rx: aggregation info for Rx per TID
+ * @tid_tx: aggregation info for Tx per TID
* @ampdu_rx: for locking sections in aggregation Rx flow
+ * @ampdu_tx: for locking sectionsi in aggregation Tx flow
+ * @dialog_token_allocator: dialog token enumerator for each new session;
*/
struct sta_ampdu_mlme {
struct tid_ampdu_rx tid_rx[STA_TID_NUM];
+ struct tid_ampdu_tx tid_tx[STA_TID_NUM];
spinlock_t ampdu_rx;
+ spinlock_t ampdu_tx;
+ u8 dialog_token_allocator;
};
+
+/* see __sta_info_unlink */
+#define STA_INFO_PIN_STAT_NORMAL 0
+#define STA_INFO_PIN_STAT_PINNED 1
+#define STA_INFO_PIN_STAT_DESTROY 2
+
+/**
+ * struct sta_info - STA information
+ *
+ * This structure collects information about a station that
+ * mac80211 is communicating with.
+ *
+ * @list: global linked list entry
+ * @hnext: hash table linked list pointer
+ * @local: pointer to the global information
+ * @addr: MAC address of this STA
+ * @aid: STA's unique AID (1..2007, 0 = not assigned yet),
+ * only used in AP (and IBSS?) mode
+ * @flags: STA flags, see &enum ieee80211_sta_info_flags
+ * @ps_tx_buf: buffer of frames to transmit to this station
+ * when it leaves power saving state
+ * @tx_filtered: buffer of frames we already tried to transmit
+ * but were filtered by hardware due to STA having entered
+ * power saving state
+ * @rx_packets: Number of MSDUs received from this STA
+ * @rx_bytes: Number of bytes received from this STA
+ * @supp_rates: Bitmap of supported rates (per band)
+ * @ht_info: HT capabilities of this STA
+ */
struct sta_info {
- struct kref kref;
+ /* General information, mostly static */
struct list_head list;
- struct sta_info *hnext; /* next entry in hash table list */
-
+ struct sta_info *hnext;
struct ieee80211_local *local;
-
- u8 addr[ETH_ALEN];
- u16 aid; /* STA's unique AID (1..2007), 0 = not yet assigned */
- u32 flags; /* WLAN_STA_ */
-
- struct sk_buff_head ps_tx_buf; /* buffer of TX frames for station in
- * power saving state */
- int pspoll; /* whether STA has send a PS Poll frame */
- struct sk_buff_head tx_filtered; /* buffer of TX frames that were
- * already given to low-level driver,
- * but were filtered */
- int clear_dst_mask;
-
- unsigned long rx_packets, tx_packets; /* number of RX/TX MSDUs */
- unsigned long rx_bytes, tx_bytes;
- unsigned long tx_retry_failed, tx_retry_count;
- unsigned long tx_filtered_count;
-
- unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */
-
- unsigned long last_rx;
- u32 supp_rates; /* bitmap of supported rates in local->curr_rates */
- int txrate; /* index in local->curr_rates */
- int last_txrate; /* last rate used to send a frame to this STA */
- int last_nonerp_idx;
-
- struct net_device *dev; /* which net device is this station associated
- * to */
-
+ struct ieee80211_sub_if_data *sdata;
struct ieee80211_key *key;
-
- u32 tx_num_consecutive_failures;
- u32 tx_num_mpdu_ok;
- u32 tx_num_mpdu_fail;
-
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;
+ struct ieee80211_ht_info ht_info;
+ u64 supp_rates[IEEE80211_NUM_BANDS];
+ u8 addr[ETH_ALEN];
+ u16 aid;
+ u16 listen_interval;
- /* last received seq/frag number from this STA (per RX queue) */
- __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
+ /*
+ * for use by the internal lifetime management,
+ * see __sta_info_unlink
+ */
+ u8 pin_status;
+
+ /* frequently updated information, needs locking? */
+ u32 flags;
+
+ /*
+ * STA powersave frame queues, no more than the internal
+ * locking required.
+ */
+ struct sk_buff_head ps_tx_buf;
+ struct sk_buff_head tx_filtered;
+
+ /* Updated from RX path only, no locking requirements */
+ unsigned long rx_packets, rx_bytes;
+ unsigned long wep_weak_iv_count;
+ unsigned long last_rx;
unsigned long num_duplicates; /* number of duplicate frames received
* from this STA */
- unsigned long tx_fragments; /* number of transmitted MPDUs */
unsigned long rx_fragments; /* number of received MPDUs */
unsigned long rx_dropped; /* number of dropped MPDUs from this STA */
-
int last_rssi; /* RSSI of last received frame from this STA */
int last_signal; /* signal of last received frame from this STA */
int last_noise; /* noise of last received frame from this STA */
- int last_ack_rssi[3]; /* RSSI of last received ACKs from this STA */
- unsigned long last_ack;
- int channel_use;
- int channel_use_raw;
-
+ /* last received seq/frag number from this STA (per RX queue) */
+ __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
+#endif
+
+ /* Updated from TX status path only, no locking requirements */
+ unsigned long tx_filtered_count;
+ unsigned long tx_retry_failed, tx_retry_count;
+ /* TODO: update in generic code not rate control? */
+ u32 tx_num_consecutive_failures;
+ u32 tx_num_mpdu_ok;
+ u32 tx_num_mpdu_fail;
+ /* moving percentage of failed MSDUs */
+ unsigned int fail_avg;
+
+ /* Updated from TX path only, no locking requirements */
+ unsigned long tx_packets; /* number of RX/TX MSDUs */
+ unsigned long tx_bytes;
+ unsigned long tx_fragments; /* number of transmitted MPDUs */
+ int txrate_idx;
+ int last_txrate_idx;
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
-#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+#endif
- u16 listen_interval;
+ /* Debug counters, no locking doesn't matter */
+ int channel_use;
+ int channel_use_raw;
- struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities
- of this STA */
+ /*
+ * Aggregation information, comes with own locking.
+ */
struct sta_ampdu_mlme ampdu_mlme;
- u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */
+ u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */
+ u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */
+
+#ifdef CONFIG_MAC80211_MESH
+ /*
+ * Mesh peer link attributes
+ * TODO: move to a sub-structure that is referenced with pointer?
+ */
+ __le16 llid; /* Local link ID */
+ __le16 plid; /* Peer link ID */
+ __le16 reason; /* Cancel reason on PLINK_HOLDING state */
+ u8 plink_retries; /* Retries in establishment */
+ bool ignore_plink_timer;
+ enum plink_state plink_state;
+ u32 plink_timeout;
+ struct timer_list plink_timer;
+ spinlock_t plink_lock; /* For peer_state reads / updates and other
+ updates in the structure. Ensures robust
+ transitions for the peerlink FSM */
+#endif
#ifdef CONFIG_MAC80211_DEBUGFS
struct sta_info_debugfsdentries {
struct dentry *dir;
struct dentry *flags;
struct dentry *num_ps_buf_frames;
- struct dentry *last_ack_rssi;
- struct dentry *last_ack_ms;
struct dentry *inactive_ms;
struct dentry *last_seq_ctrl;
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
struct dentry *wme_rx_queue;
struct dentry *wme_tx_queue;
#endif
+ struct dentry *agg_status;
} debugfs;
#endif
};
+static inline enum plink_state sta_plink_state(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return sta->plink_state;
+#endif
+ return PLINK_LISTEN;
+}
+
/* Maximum number of concurrently registered stations */
#define MAX_STA_COUNT 2007
*/
#define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
-static inline void __sta_info_get(struct sta_info *sta)
-{
- kref_get(&sta->kref);
-}
+/*
+ * Get a STA info, must have be under RCU read lock.
+ */
+struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr);
+/*
+ * Get STA info by index, BROKEN!
+ */
+struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
+ struct net_device *dev);
+/*
+ * Create a new STA info, caller owns returned structure
+ * until sta_info_insert().
+ */
+struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
+ u8 *addr, gfp_t gfp);
+/*
+ * Insert STA info into hash table/list, returns zero or a
+ * -EEXIST if (if the same MAC address is already present).
+ *
+ * Calling this without RCU protection makes the caller
+ * relinquish its reference to @sta.
+ */
+int sta_info_insert(struct sta_info *sta);
+/*
+ * Unlink a STA info from the hash table/list.
+ * This can NULL the STA pointer if somebody else
+ * has already unlinked it.
+ */
+void sta_info_unlink(struct sta_info **sta);
+
+void sta_info_destroy(struct sta_info *sta);
+void sta_info_set_tim_bit(struct sta_info *sta);
+void sta_info_clear_tim_bit(struct sta_info *sta);
-struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
-int sta_info_min_txrate_get(struct ieee80211_local *local);
-void sta_info_put(struct sta_info *sta);
-struct sta_info * sta_info_add(struct ieee80211_local *local,
- struct net_device *dev, u8 *addr, gfp_t gfp);
-void sta_info_remove(struct sta_info *sta);
-void sta_info_free(struct sta_info *sta);
void sta_info_init(struct ieee80211_local *local);
int sta_info_start(struct ieee80211_local *local);
void sta_info_stop(struct ieee80211_local *local);
-void sta_info_remove_aid_ptr(struct sta_info *sta);
-void sta_info_flush(struct ieee80211_local *local, struct net_device *dev);
+int sta_info_flush(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata);
#endif /* STA_INFO_H */
#include "ieee80211_i.h"
#include "ieee80211_led.h"
+#include "mesh.h"
#include "wep.h"
#include "wpa.h"
#include "wme.h"
}
#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
-static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
+static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
int next_frag_len)
{
int rate, mrate, erp, dur, i;
- struct ieee80211_rate *txrate = tx->u.tx.rate;
+ struct ieee80211_rate *txrate = tx->rate;
struct ieee80211_local *local = tx->local;
- struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+ struct ieee80211_supported_band *sband;
- erp = txrate->flags & IEEE80211_RATE_ERP;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ erp = 0;
+ if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = txrate->flags & IEEE80211_RATE_ERP_G;
/*
* data and mgmt (except PS Poll):
* Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
*/
rate = -1;
- mrate = 10; /* use 1 Mbps if everything fails */
- for (i = 0; i < mode->num_rates; i++) {
- struct ieee80211_rate *r = &mode->rates[i];
- if (r->rate > txrate->rate)
- break;
+ /* use lowest available if everything fails */
+ mrate = sband->bitrates[0].bitrate;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ struct ieee80211_rate *r = &sband->bitrates[i];
- if (IEEE80211_RATE_MODULATION(txrate->flags) !=
- IEEE80211_RATE_MODULATION(r->flags))
- continue;
+ if (r->bitrate > txrate->bitrate)
+ break;
- if (r->flags & IEEE80211_RATE_BASIC)
- rate = r->rate;
- else if (r->flags & IEEE80211_RATE_MANDATORY)
- mrate = r->rate;
+ if (tx->sdata->basic_rates & BIT(i))
+ rate = r->bitrate;
+
+ switch (sband->band) {
+ case IEEE80211_BAND_2GHZ: {
+ u32 flag;
+ if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ flag = IEEE80211_RATE_MANDATORY_G;
+ else
+ flag = IEEE80211_RATE_MANDATORY_B;
+ if (r->flags & flag)
+ mrate = r->bitrate;
+ break;
+ }
+ case IEEE80211_BAND_5GHZ:
+ if (r->flags & IEEE80211_RATE_MANDATORY_A)
+ mrate = r->bitrate;
+ break;
+ case IEEE80211_NUM_BANDS:
+ WARN_ON(1);
+ break;
+ }
}
if (rate == -1) {
/* No matching basic rate found; use highest suitable mandatory
dur *= 2; /* ACK + SIFS */
/* next fragment */
dur += ieee80211_frame_duration(local, next_frag_len,
- txrate->rate, erp,
+ txrate->bitrate, erp,
tx->sdata->bss_conf.use_short_preamble);
}
/* tx handlers */
-static ieee80211_txrx_result
-ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
{
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
struct sk_buff *skb = tx->skb;
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
u32 sta_flags;
- if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED))
- return TXRX_CONTINUE;
+ if (unlikely(tx->flags & IEEE80211_TX_INJECTED))
+ return TX_CONTINUE;
if (unlikely(tx->local->sta_sw_scanning) &&
((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
(tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
- return TXRX_DROP;
+ return TX_DROP;
- if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)
- return TXRX_CONTINUE;
+ if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ return TX_CONTINUE;
+
+ if (tx->flags & IEEE80211_TX_PS_BUFFERED)
+ return TX_CONTINUE;
sta_flags = tx->sta ? tx->sta->flags : 0;
- if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) {
+ if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
(tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
tx->dev->name, print_mac(mac, hdr->addr1));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
- return TXRX_DROP;
+ return TX_DROP;
}
} else {
if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
* No associated STAs - no need to send multicast
* frames.
*/
- return TXRX_DROP;
+ return TX_DROP;
}
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
ieee80211_include_sequence(tx->sdata, hdr);
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
/* This function is called whenever the AP is about to exceed the maximum limit
}
total += skb_queue_len(&ap->ps_bc_buf);
}
- rcu_read_unlock();
- read_lock_bh(&local->sta_lock);
- list_for_each_entry(sta, &local->sta_list, list) {
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
skb = skb_dequeue(&sta->ps_tx_buf);
if (skb) {
purged++;
}
total += skb_queue_len(&sta->ps_tx_buf);
}
- read_unlock_bh(&local->sta_lock);
+
+ rcu_read_unlock();
local->total_ps_buffered = total;
printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
wiphy_name(local->hw.wiphy), purged);
}
-static ieee80211_txrx_result
-ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
{
/*
* broadcast/multicast frame
/* not AP/IBSS or ordered frame */
if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER))
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
/* no stations in PS mode */
if (!atomic_read(&tx->sdata->bss->num_sta_ps))
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
/* buffered in mac80211 */
if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) {
} else
tx->local->total_ps_buffered++;
skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
- return TXRX_QUEUED;
+ return TX_QUEUED;
}
/* buffered in hardware */
- tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
+ tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
{
struct sta_info *sta = tx->sta;
DECLARE_MAC_BUF(mac);
if (unlikely(!sta ||
((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
(tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
- if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) {
+ if (unlikely((sta->flags & WLAN_STA_PS) &&
+ !(sta->flags & WLAN_STA_PSPOLL))) {
struct ieee80211_tx_packet_data *pkt_data;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
print_mac(mac, sta->addr), sta->aid,
skb_queue_len(&sta->ps_tx_buf));
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- sta->flags |= WLAN_STA_TIM;
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local);
if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
dev_kfree_skb(old);
} else
tx->local->total_ps_buffered++;
+
/* Queue frame to be sent after STA sends an PS Poll frame */
- if (skb_queue_empty(&sta->ps_tx_buf)) {
- if (tx->local->ops->set_tim)
- tx->local->ops->set_tim(local_to_hw(tx->local),
- sta->aid, 1);
- if (tx->sdata->bss)
- bss_tim_set(tx->local, tx->sdata->bss, sta->aid);
- }
+ if (skb_queue_empty(&sta->ps_tx_buf))
+ sta_info_set_tim_bit(sta);
+
pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
pkt_data->jiffies = jiffies;
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
- return TXRX_QUEUED;
+ return TX_QUEUED;
}
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
else if (unlikely(sta->flags & WLAN_STA_PS)) {
print_mac(mac, sta->addr));
}
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- sta->pspoll = 0;
+ sta->flags &= ~WLAN_STA_PSPOLL;
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
{
- if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED))
- return TXRX_CONTINUE;
+ if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
+ return TX_CONTINUE;
- if (tx->flags & IEEE80211_TXRXD_TXUNICAST)
+ if (tx->flags & IEEE80211_TX_UNICAST)
return ieee80211_tx_h_unicast_ps_buf(tx);
else
return ieee80211_tx_h_multicast_ps_buf(tx);
}
-static ieee80211_txrx_result
-ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{
struct ieee80211_key *key;
u16 fc = tx->fc;
- if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+ if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
tx->key = key;
else if ((key = rcu_dereference(tx->sdata->default_key)))
tx->key = key;
else if (tx->sdata->drop_unencrypted &&
- !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
- !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) {
+ !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
+ !(tx->flags & IEEE80211_TX_INJECTED)) {
I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
- return TXRX_DROP;
+ return TX_DROP;
} else
tx->key = NULL;
}
if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
- tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+ tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
size_t hdrlen, per_fragm, num_fragm, payload_len, left;
u8 *pos;
int frag_threshold = tx->local->fragmentation_threshold;
- if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED))
- return TXRX_CONTINUE;
+ if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
+ return TX_CONTINUE;
first = tx->skb;
}
skb_trim(first, hdrlen + per_fragm);
- tx->u.tx.num_extra_frag = num_fragm - 1;
- tx->u.tx.extra_frag = frags;
+ tx->num_extra_frag = num_fragm - 1;
+ tx->extra_frag = frags;
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
fail:
printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
kfree(frags);
}
I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
- return TXRX_DROP;
+ return TX_DROP;
}
-static ieee80211_txrx_result
-ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
{
if (!tx->key)
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
switch (tx->key->conf.alg) {
case ALG_WEP:
/* not reached */
WARN_ON(1);
- return TXRX_DROP;
+ return TX_DROP;
}
-static ieee80211_txrx_result
-ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
{
struct rate_selection rsel;
+ struct ieee80211_supported_band *sband;
+
+ sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
- if (likely(!tx->u.tx.rate)) {
- rate_control_get_rate(tx->dev, tx->u.tx.mode, tx->skb, &rsel);
- tx->u.tx.rate = rsel.rate;
- if (unlikely(rsel.probe != NULL)) {
- tx->u.tx.control->flags |=
+ if (likely(!tx->rate)) {
+ rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+ tx->rate = rsel.rate;
+ if (unlikely(rsel.probe)) {
+ tx->control->flags |=
IEEE80211_TXCTL_RATE_CTRL_PROBE;
- tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
- tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val;
- tx->u.tx.rate = rsel.probe;
+ tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+ tx->control->alt_retry_rate = tx->rate;
+ tx->rate = rsel.probe;
} else
- tx->u.tx.control->alt_retry_rate = -1;
+ tx->control->alt_retry_rate = NULL;
- if (!tx->u.tx.rate)
- return TXRX_DROP;
+ if (!tx->rate)
+ return TX_DROP;
} else
- tx->u.tx.control->alt_retry_rate = -1;
+ tx->control->alt_retry_rate = NULL;
- if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
- tx->sdata->bss_conf.use_cts_prot &&
- (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) {
- tx->u.tx.last_frag_rate = tx->u.tx.rate;
+ if (tx->sdata->bss_conf.use_cts_prot &&
+ (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) {
+ tx->last_frag_rate = tx->rate;
if (rsel.probe)
- tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
+ tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
else
- tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
- tx->u.tx.rate = rsel.nonerp;
- tx->u.tx.control->rate = rsel.nonerp;
- tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+ tx->rate = rsel.nonerp;
+ tx->control->tx_rate = rsel.nonerp;
+ tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
} else {
- tx->u.tx.last_frag_rate = tx->u.tx.rate;
- tx->u.tx.control->rate = tx->u.tx.rate;
+ tx->last_frag_rate = tx->rate;
+ tx->control->tx_rate = tx->rate;
}
- tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
+ tx->control->tx_rate = tx->rate;
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
u16 fc = le16_to_cpu(hdr->frame_control);
u16 dur;
- struct ieee80211_tx_control *control = tx->u.tx.control;
- struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+ struct ieee80211_tx_control *control = tx->control;
if (!control->retry_limit) {
if (!is_multicast_ether_addr(hdr->addr1)) {
}
}
- if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) {
+ if (tx->flags & IEEE80211_TX_FRAGMENTED) {
/* Do not use multiple retry rates when sending fragmented
* frames.
* TODO: The last fragment could still use multiple retry
* rates. */
- control->alt_retry_rate = -1;
+ control->alt_retry_rate = NULL;
}
/* Use CTS protection for unicast frames sent using extended rates if
* there are associated non-ERP stations and RTS/CTS is not configured
* for the frame. */
- if (mode->mode == MODE_IEEE80211G &&
- (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
- (tx->flags & IEEE80211_TXRXD_TXUNICAST) &&
+ if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+ (tx->rate->flags & IEEE80211_RATE_ERP_G) &&
+ (tx->flags & IEEE80211_TX_UNICAST) &&
tx->sdata->bss_conf.use_cts_prot &&
!(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
* short preambles at the selected rate and short preambles are
* available on the network at the current point in time. */
if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
- (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
+ (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
tx->sdata->bss_conf.use_short_preamble &&
(!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
- tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+ tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
}
/* Setup duration field for the first fragment of the frame. Duration
* for remaining fragments will be updated when they are being sent
* to low-level driver in ieee80211_tx(). */
dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
- (tx->flags & IEEE80211_TXRXD_FRAGMENTED) ?
- tx->u.tx.extra_frag[0]->len : 0);
+ (tx->flags & IEEE80211_TX_FRAGMENTED) ?
+ tx->extra_frag[0]->len : 0);
hdr->duration_id = cpu_to_le16(dur);
if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
(control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
- struct ieee80211_rate *rate;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *rate, *baserate;
+ int idx;
+
+ sband = tx->local->hw.wiphy->bands[
+ tx->local->hw.conf.channel->band];
/* Do not use multiple retry rates when using RTS/CTS */
- control->alt_retry_rate = -1;
+ control->alt_retry_rate = NULL;
/* Use min(data rate, max base rate) as CTS/RTS rate */
- rate = tx->u.tx.rate;
- while (rate > mode->rates &&
- !(rate->flags & IEEE80211_RATE_BASIC))
- rate--;
+ rate = tx->rate;
+ baserate = NULL;
+
+ for (idx = 0; idx < sband->n_bitrates; idx++) {
+ if (sband->bitrates[idx].bitrate > rate->bitrate)
+ continue;
+ if (tx->sdata->basic_rates & BIT(idx) &&
+ (!baserate ||
+ (baserate->bitrate < sband->bitrates[idx].bitrate)))
+ baserate = &sband->bitrates[idx];
+ }
- control->rts_cts_rate = rate->val;
- control->rts_rate = rate;
+ if (baserate)
+ control->rts_cts_rate = baserate;
+ else
+ control->rts_cts_rate = &sband->bitrates[0];
}
if (tx->sta) {
tx->sta->tx_packets++;
tx->sta->tx_fragments++;
tx->sta->tx_bytes += tx->skb->len;
- if (tx->u.tx.extra_frag) {
+ if (tx->extra_frag) {
int i;
- tx->sta->tx_fragments += tx->u.tx.num_extra_frag;
- for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ tx->sta->tx_fragments += tx->num_extra_frag;
+ for (i = 0; i < tx->num_extra_frag; i++) {
tx->sta->tx_bytes +=
- tx->u.tx.extra_frag[i]->len;
+ tx->extra_frag[i]->len;
}
}
}
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-static ieee80211_txrx_result
-ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx)
{
struct ieee80211_local *local = tx->local;
- struct ieee80211_hw_mode *mode = tx->u.tx.mode;
struct sk_buff *skb = tx->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u32 load = 0, hdrtime;
+ struct ieee80211_rate *rate = tx->rate;
/* TODO: this could be part of tx_status handling, so that the number
* of retries would be known; TX rate should in that case be stored
/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
* 1 usec = 1/8 * (1080 / 10) = 13.5 */
- if (mode->mode == MODE_IEEE80211A ||
- (mode->mode == MODE_IEEE80211G &&
- tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
+ if (tx->channel->band == IEEE80211_BAND_5GHZ ||
+ (tx->channel->band == IEEE80211_BAND_2GHZ &&
+ rate->flags & IEEE80211_RATE_ERP_G))
hdrtime = CHAN_UTIL_HDR_SHORT;
else
hdrtime = CHAN_UTIL_HDR_LONG;
if (!is_multicast_ether_addr(hdr->addr1))
load += hdrtime;
- if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
load += 2 * hdrtime;
- else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
load += hdrtime;
- load += skb->len * tx->u.tx.rate->rate_inv;
+ /* TODO: optimise again */
+ load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
- if (tx->u.tx.extra_frag) {
+ if (tx->extra_frag) {
int i;
- for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ for (i = 0; i < tx->num_extra_frag; i++) {
load += 2 * hdrtime;
- load += tx->u.tx.extra_frag[i]->len *
- tx->u.tx.rate->rate;
+ load += tx->extra_frag[i]->len *
+ tx->rate->bitrate;
}
}
tx->sta->channel_use_raw += load;
tx->sdata->channel_use_raw += load;
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-/* TODO: implement register/unregister functions for adding TX/RX handlers
- * into ordered list */
-ieee80211_tx_handler ieee80211_tx_handlers[] =
+typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_tx_data *);
+static ieee80211_tx_handler ieee80211_tx_handlers[] =
{
ieee80211_tx_h_check_assoc,
ieee80211_tx_h_sequence,
* deal with packet injection down monitor interface
* with Radiotap Header -- only called for monitor mode interface
*/
-static ieee80211_txrx_result
-__ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
+static ieee80211_tx_result
+__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
struct sk_buff *skb)
{
/*
struct ieee80211_radiotap_iterator iterator;
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
- struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode;
+ struct ieee80211_supported_band *sband;
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
- struct ieee80211_tx_control *control = tx->u.tx.control;
+ struct ieee80211_tx_control *control = tx->control;
+
+ sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
- tx->flags |= IEEE80211_TXRXD_TX_INJECTED;
- tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED;
+ tx->flags |= IEEE80211_TX_INJECTED;
+ tx->flags &= ~IEEE80211_TX_FRAGMENTED;
/*
* for every radiotap entry that is present
* ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
*/
target_rate = (*iterator.this_arg) * 5;
- for (i = 0; i < mode->num_rates; i++) {
- struct ieee80211_rate *r = &mode->rates[i];
+ for (i = 0; i < sband->n_bitrates; i++) {
+ struct ieee80211_rate *r;
+
+ r = &sband->bitrates[i];
- if (r->rate == target_rate) {
- tx->u.tx.rate = r;
+ if (r->bitrate == target_rate) {
+ tx->rate = r;
break;
}
}
control->antenna_sel_tx = (*iterator.this_arg) + 1;
break;
+#if 0
case IEEE80211_RADIOTAP_DBM_TX_POWER:
control->power_level = *iterator.this_arg;
break;
+#endif
case IEEE80211_RADIOTAP_FLAGS:
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
* on transmission
*/
if (skb->len < (iterator.max_length + FCS_LEN))
- return TXRX_DROP;
+ return TX_DROP;
skb_trim(skb, skb->len - FCS_LEN);
}
control->flags &=
~IEEE80211_TXCTL_DO_NOT_ENCRYPT;
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
- tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+ tx->flags |= IEEE80211_TX_FRAGMENTED;
break;
/*
}
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
- return TXRX_DROP;
+ return TX_DROP;
/*
* remove the radiotap header
*/
skb_pull(skb, iterator.max_length);
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
/*
* initialises @tx
*/
-static ieee80211_txrx_result
-__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+static ieee80211_tx_result
+__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
struct net_device *dev,
struct ieee80211_tx_control *control)
tx->dev = dev; /* use original interface */
tx->local = local;
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- tx->u.tx.control = control;
+ tx->control = control;
/*
* Set this flag (used below to indicate "automatic fragmentation"),
* it will be cleared/left by radiotap as desired.
*/
- tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+ tx->flags |= IEEE80211_TX_FRAGMENTED;
/* process and remove the injection radiotap header */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) {
- if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP)
- return TXRX_DROP;
+ if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
+ return TX_DROP;
/*
* __ieee80211_parse_tx_radiotap has now removed
tx->fc = le16_to_cpu(hdr->frame_control);
if (is_multicast_ether_addr(hdr->addr1)) {
- tx->flags &= ~IEEE80211_TXRXD_TXUNICAST;
+ tx->flags &= ~IEEE80211_TX_UNICAST;
control->flags |= IEEE80211_TXCTL_NO_ACK;
} else {
- tx->flags |= IEEE80211_TXRXD_TXUNICAST;
+ tx->flags |= IEEE80211_TX_UNICAST;
control->flags &= ~IEEE80211_TXCTL_NO_ACK;
}
- if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) {
- if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) &&
+ if (tx->flags & IEEE80211_TX_FRAGMENTED) {
+ if ((tx->flags & IEEE80211_TX_UNICAST) &&
skb->len + FCS_LEN > local->fragmentation_threshold &&
!local->ops->set_frag_threshold)
- tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+ tx->flags |= IEEE80211_TX_FRAGMENTED;
else
- tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED;
+ tx->flags &= ~IEEE80211_TX_FRAGMENTED;
}
if (!tx->sta)
- control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
- else if (tx->sta->clear_dst_mask) {
- control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
- tx->sta->clear_dst_mask = 0;
+ control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
+ else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) {
+ control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
+ tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT;
}
hdrlen = ieee80211_get_hdrlen(tx->fc);
}
control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
/*
* NB: @tx is uninitialised when passed in here
*/
-static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
struct net_device *mdev,
struct ieee80211_tx_control *control)
}
static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
- struct ieee80211_txrx_data *tx)
+ struct ieee80211_tx_data *tx)
{
- struct ieee80211_tx_control *control = tx->u.tx.control;
+ struct ieee80211_tx_control *control = tx->control;
int ret, i;
if (!ieee80211_qdisc_installed(local->mdev) &&
local->mdev->trans_start = jiffies;
ieee80211_led_tx(local, 1);
}
- if (tx->u.tx.extra_frag) {
+ if (tx->extra_frag) {
control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
IEEE80211_TXCTL_USE_CTS_PROTECT |
- IEEE80211_TXCTL_CLEAR_DST_MASK |
+ IEEE80211_TXCTL_CLEAR_PS_FILT |
IEEE80211_TXCTL_FIRST_FRAGMENT);
- for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
- if (!tx->u.tx.extra_frag[i])
+ for (i = 0; i < tx->num_extra_frag; i++) {
+ if (!tx->extra_frag[i])
continue;
if (__ieee80211_queue_stopped(local, control->queue))
return IEEE80211_TX_FRAG_AGAIN;
- if (i == tx->u.tx.num_extra_frag) {
- control->tx_rate = tx->u.tx.last_frag_hwrate;
- control->rate = tx->u.tx.last_frag_rate;
- if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG)
+ if (i == tx->num_extra_frag) {
+ control->tx_rate = tx->last_frag_rate;
+
+ if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
control->flags |=
IEEE80211_TXCTL_RATE_CTRL_PROBE;
else
ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
"TX to low-level driver",
- tx->u.tx.extra_frag[i]);
+ tx->extra_frag[i]);
ret = local->ops->tx(local_to_hw(local),
- tx->u.tx.extra_frag[i],
+ tx->extra_frag[i],
control);
if (ret)
return IEEE80211_TX_FRAG_AGAIN;
local->mdev->trans_start = jiffies;
ieee80211_led_tx(local, 1);
- tx->u.tx.extra_frag[i] = NULL;
+ tx->extra_frag[i] = NULL;
}
- kfree(tx->u.tx.extra_frag);
- tx->u.tx.extra_frag = NULL;
+ kfree(tx->extra_frag);
+ tx->extra_frag = NULL;
}
return IEEE80211_TX_OK;
}
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
ieee80211_tx_handler *handler;
- struct ieee80211_txrx_data tx;
- ieee80211_txrx_result res = TXRX_DROP, res_prepare;
+ struct ieee80211_tx_data tx;
+ ieee80211_tx_result res = TX_DROP, res_prepare;
int ret, i;
WARN_ON(__ieee80211_queue_pending(local, control->queue));
return 0;
}
+ rcu_read_lock();
+
/* initialises tx */
res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
- if (res_prepare == TXRX_DROP) {
+ if (res_prepare == TX_DROP) {
dev_kfree_skb(skb);
+ rcu_read_unlock();
return 0;
}
- /*
- * key references are protected using RCU and this requires that
- * we are in a read-site RCU section during receive processing
- */
- rcu_read_lock();
-
sta = tx.sta;
- tx.u.tx.mode = local->hw.conf.mode;
+ tx.channel = local->hw.conf.channel;
- for (handler = local->tx_handlers; *handler != NULL;
+ for (handler = ieee80211_tx_handlers; *handler != NULL;
handler++) {
res = (*handler)(&tx);
- if (res != TXRX_CONTINUE)
+ if (res != TX_CONTINUE)
break;
}
skb = tx.skb; /* handlers are allowed to change skb */
- if (sta)
- sta_info_put(sta);
-
- if (unlikely(res == TXRX_DROP)) {
+ if (unlikely(res == TX_DROP)) {
I802_DEBUG_INC(local->tx_handlers_drop);
goto drop;
}
- if (unlikely(res == TXRX_QUEUED)) {
+ if (unlikely(res == TX_QUEUED)) {
I802_DEBUG_INC(local->tx_handlers_queued);
rcu_read_unlock();
return 0;
}
- if (tx.u.tx.extra_frag) {
- for (i = 0; i < tx.u.tx.num_extra_frag; i++) {
+ if (tx.extra_frag) {
+ for (i = 0; i < tx.num_extra_frag; i++) {
int next_len, dur;
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *)
- tx.u.tx.extra_frag[i]->data;
+ tx.extra_frag[i]->data;
- if (i + 1 < tx.u.tx.num_extra_frag) {
- next_len = tx.u.tx.extra_frag[i + 1]->len;
+ if (i + 1 < tx.num_extra_frag) {
+ next_len = tx.extra_frag[i + 1]->len;
} else {
next_len = 0;
- tx.u.tx.rate = tx.u.tx.last_frag_rate;
- tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val;
+ tx.rate = tx.last_frag_rate;
}
dur = ieee80211_duration(&tx, 0, next_len);
hdr->duration_id = cpu_to_le16(dur);
memcpy(&store->control, control,
sizeof(struct ieee80211_tx_control));
store->skb = skb;
- store->extra_frag = tx.u.tx.extra_frag;
- store->num_extra_frag = tx.u.tx.num_extra_frag;
- store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
- store->last_frag_rate = tx.u.tx.last_frag_rate;
+ store->extra_frag = tx.extra_frag;
+ store->num_extra_frag = tx.num_extra_frag;
+ store->last_frag_rate = tx.last_frag_rate;
store->last_frag_rate_ctrl_probe =
- !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG);
+ !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
}
rcu_read_unlock();
return 0;
drop:
if (skb)
dev_kfree_skb(skb);
- for (i = 0; i < tx.u.tx.num_extra_frag; i++)
- if (tx.u.tx.extra_frag[i])
- dev_kfree_skb(tx.u.tx.extra_frag[i]);
- kfree(tx.u.tx.extra_frag);
+ for (i = 0; i < tx.num_extra_frag; i++)
+ if (tx.extra_frag[i])
+ dev_kfree_skb(tx.extra_frag[i]);
+ kfree(tx.extra_frag);
rcu_read_unlock();
return 0;
}
control.flags |= IEEE80211_TXCTL_REQUEUE;
if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME)
control.flags |= IEEE80211_TXCTL_EAPOL_FRAME;
+ if (pkt_data->flags & IEEE80211_TXPD_AMPDU)
+ control.flags |= IEEE80211_TXCTL_AMPDU;
control.queue = pkt_data->queue;
ret = ieee80211_tx(odev, skb, &control);
struct ieee80211_tx_packet_data *pkt_data;
struct ieee80211_sub_if_data *sdata;
int ret = 1, head_need;
- u16 ethertype, hdrlen, fc;
+ u16 ethertype, hdrlen, meshhdrlen = 0, fc;
struct ieee80211_hdr hdr;
+ struct ieee80211s_hdr mesh_hdr;
const u8 *encaps_data;
int encaps_len, skip_header_bytes;
int nh_pos, h_pos;
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 30;
break;
+#ifdef CONFIG_MAC80211_MESH
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+ /* RA TA DA SA */
+ if (is_multicast_ether_addr(skb->data))
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ else if (mesh_nexthop_lookup(hdr.addr1, skb, dev))
+ return 0;
+ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+ memcpy(hdr.addr3, skb->data, ETH_ALEN);
+ memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+ if (skb->pkt_type == PACKET_OTHERHOST) {
+ /* Forwarded frame, keep mesh ttl and seqnum */
+ struct ieee80211s_hdr *prev_meshhdr;
+ prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb);
+ meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr);
+ memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen);
+ sdata->u.sta.mshstats.fwded_frames++;
+ } else {
+ if (!sdata->u.sta.mshcfg.dot11MeshTTL) {
+ /* Do not send frames with mesh_ttl == 0 */
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ ret = 0;
+ goto fail;
+ }
+ meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
+ sdata);
+ }
+ hdrlen = 30;
+ break;
+#endif
case IEEE80211_IF_TYPE_STA:
fc |= IEEE80211_FCTL_TODS;
/* BSSID SA DA */
goto fail;
}
- sta = sta_info_get(local, hdr.addr1);
- if (sta) {
- sta_flags = sta->flags;
- sta_info_put(sta);
+ /*
+ * There's no need to try to look up the destination
+ * if it is a multicast address (which can only happen
+ * in AP mode)
+ */
+ if (!is_multicast_ether_addr(hdr.addr1)) {
+ rcu_read_lock();
+ sta = sta_info_get(local, hdr.addr1);
+ if (sta)
+ sta_flags = sta->flags;
+ rcu_read_unlock();
}
/* receiver is QoS enabled, use a QoS type frame */
}
/*
- * If port access control is enabled, drop frames to unauthorised
- * stations unless they are EAPOL frames from the local station.
+ * Drop unicast frames to unauthorised stations unless they are
+ * EAPOL frames from the local station.
*/
- if (unlikely(sdata->ieee802_1x_pac &&
- !(sta_flags & WLAN_STA_AUTHORIZED) &&
- !(ethertype == ETH_P_PAE &&
+ if (unlikely(!is_multicast_ether_addr(hdr.addr1) &&
+ !(sta_flags & WLAN_STA_AUTHORIZED) &&
+ !(ethertype == ETH_P_PAE &&
compare_ether_addr(dev->dev_addr,
skb->data + ETH_ALEN) == 0))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
* build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
* alloc_skb() (net/core/skbuff.c)
*/
- head_need = hdrlen + encaps_len + local->tx_headroom;
+ head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom;
head_need -= skb_headroom(skb);
/* We are going to modify skb data, so make a copy of it if happens to
h_pos += encaps_len;
}
+ if (meshhdrlen > 0) {
+ memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
+ nh_pos += meshhdrlen;
+ h_pos += meshhdrlen;
+ }
+
if (fc & IEEE80211_STYPE_QOS_DATA) {
__le16 *qos_control;
struct ieee80211_local *local = (struct ieee80211_local *)data;
struct net_device *dev = local->mdev;
struct ieee80211_tx_stored_packet *store;
- struct ieee80211_txrx_data tx;
+ struct ieee80211_tx_data tx;
int i, ret, reschedule = 0;
netif_tx_lock_bh(dev);
continue;
}
store = &local->pending_packet[i];
- tx.u.tx.control = &store->control;
- tx.u.tx.extra_frag = store->extra_frag;
- tx.u.tx.num_extra_frag = store->num_extra_frag;
- tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
- tx.u.tx.last_frag_rate = store->last_frag_rate;
+ tx.control = &store->control;
+ tx.extra_frag = store->extra_frag;
+ tx.num_extra_frag = store->num_extra_frag;
+ tx.last_frag_rate = store->last_frag_rate;
tx.flags = 0;
if (store->last_frag_rate_ctrl_probe)
- tx.flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
+ tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
ret = __ieee80211_tx(local, store->skb, &tx);
if (ret) {
if (ret == IEEE80211_TX_FRAG_AGAIN)
/* Generate bitmap for TIM only if there are any STAs in power save
* mode. */
- read_lock_bh(&local->sta_lock);
if (atomic_read(&bss->num_sta_ps) > 0)
/* in the hope that this is faster than
* checking byte-for-byte */
*pos++ = aid0; /* Bitmap control */
*pos++ = 0; /* Part Virt Bitmap */
}
- read_unlock_bh(&local->sta_lock);
}
struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
struct ieee80211_if_ap *ap = NULL;
struct rate_selection rsel;
struct beacon_data *beacon;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_mgmt *mgmt;
+ int *num_beacons;
+ bool err = true;
+ u8 *pos;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
rcu_read_lock();
sdata = vif_to_sdata(vif);
bdev = sdata->dev;
- ap = &sdata->u.ap;
- beacon = rcu_dereference(ap->beacon);
+ if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+ ap = &sdata->u.ap;
+ beacon = rcu_dereference(ap->beacon);
+ if (ap && beacon) {
+ /*
+ * headroom, head length,
+ * tail length and maximum TIM length
+ */
+ skb = dev_alloc_skb(local->tx_headroom +
+ beacon->head_len +
+ beacon->tail_len + 256);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, local->tx_headroom);
+ memcpy(skb_put(skb, beacon->head_len), beacon->head,
+ beacon->head_len);
+
+ ieee80211_include_sequence(sdata,
+ (struct ieee80211_hdr *)skb->data);
+
+ /*
+ * Not very nice, but we want to allow the driver to call
+ * ieee80211_beacon_get() as a response to the set_tim()
+ * callback. That, however, is already invoked under the
+ * sta_lock to guarantee consistent and race-free update
+ * of the tim bitmap in mac80211 and the driver.
+ */
+ if (local->tim_in_locked_section) {
+ ieee80211_beacon_add_tim(local, ap, skb, beacon);
+ } else {
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->sta_lock, flags);
+ ieee80211_beacon_add_tim(local, ap, skb, beacon);
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+ }
+
+ if (beacon->tail)
+ memcpy(skb_put(skb, beacon->tail_len),
+ beacon->tail, beacon->tail_len);
- if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) {
+ num_beacons = &ap->num_beacons;
+
+ err = false;
+ }
+ } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ /* headroom, head length, tail length and maximum TIM length */
+ skb = dev_alloc_skb(local->tx_headroom + 400);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+ memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_BEACON);
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.beacon.beacon_int =
+ cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
+
+ pos = skb_put(skb, 2);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = 0x0;
+
+ mesh_mgmt_ies_add(skb, sdata->dev);
+
+ num_beacons = &sdata->u.sta.num_beacons;
+
+ err = false;
+ }
+
+ if (err) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "no beacon data avail for %s\n",
goto out;
}
- /* headroom, head length, tail length and maximum TIM length */
- skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
- beacon->tail_len + 256);
- if (!skb)
- goto out;
-
- skb_reserve(skb, local->tx_headroom);
- memcpy(skb_put(skb, beacon->head_len), beacon->head,
- beacon->head_len);
-
- ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
-
- ieee80211_beacon_add_tim(local, ap, skb, beacon);
-
- if (beacon->tail)
- memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
- beacon->tail_len);
-
if (control) {
- rate_control_get_rate(local->mdev, local->oper_hw_mode, skb,
- &rsel);
+ rate_control_get_rate(local->mdev, sband, skb, &rsel);
if (!rsel.rate) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
}
control->vif = vif;
- control->tx_rate =
- (sdata->bss_conf.use_short_preamble &&
- (rsel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
- rsel.rate->val2 : rsel.rate->val;
+ control->tx_rate = rsel.rate;
+ if (sdata->bss_conf.use_short_preamble &&
+ rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control->power_level = local->hw.conf.power_level;
control->flags |= IEEE80211_TXCTL_NO_ACK;
control->retry_limit = 1;
- control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+ control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
}
-
- ap->num_beacons++;
-
- out:
+ (*num_beacons)++;
+out:
rcu_read_unlock();
return skb;
}
struct sk_buff *skb;
struct sta_info *sta;
ieee80211_tx_handler *handler;
- struct ieee80211_txrx_data tx;
- ieee80211_txrx_result res = TXRX_DROP;
+ struct ieee80211_tx_data tx;
+ ieee80211_tx_result res = TX_DROP;
struct net_device *bdev;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_ap *bss = NULL;
rcu_read_unlock();
return NULL;
}
- rcu_read_unlock();
if (bss->dtim_count != 0)
return NULL; /* send buffered bc/mc only after DTIM beacon */
dev_kfree_skb_any(skb);
}
sta = tx.sta;
- tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED;
- tx.u.tx.mode = local->hw.conf.mode;
+ tx.flags |= IEEE80211_TX_PS_BUFFERED;
+ tx.channel = local->hw.conf.channel;
- for (handler = local->tx_handlers; *handler != NULL; handler++) {
+ for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
res = (*handler)(&tx);
- if (res == TXRX_DROP || res == TXRX_QUEUED)
+ if (res == TX_DROP || res == TX_QUEUED)
break;
}
skb = tx.skb; /* handlers are allowed to change skb */
- if (res == TXRX_DROP) {
+ if (res == TX_DROP) {
I802_DEBUG_INC(local->tx_handlers_drop);
dev_kfree_skb(skb);
skb = NULL;
- } else if (res == TXRX_QUEUED) {
+ } else if (res == TX_QUEUED) {
I802_DEBUG_INC(local->tx_handlers_queued);
skb = NULL;
}
- if (sta)
- sta_info_put(sta);
+ rcu_read_unlock();
return skb;
}
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
+#include "mesh.h"
#include "wme.h"
/* privid for wiphys to determine whether they belong to us or not */
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-static int rate_list_match(const int *rate_list, int rate)
-{
- int i;
-
- if (!rate_list)
- return 0;
-
- for (i = 0; rate_list[i] >= 0; i++)
- if (rate_list[i] == rate)
- return 1;
-
- return 0;
-}
-
-void ieee80211_prepare_rates(struct ieee80211_local *local,
- struct ieee80211_hw_mode *mode)
-{
- int i;
-
- for (i = 0; i < mode->num_rates; i++) {
- struct ieee80211_rate *rate = &mode->rates[i];
-
- rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
- IEEE80211_RATE_BASIC);
-
- if (local->supp_rates[mode->mode]) {
- if (!rate_list_match(local->supp_rates[mode->mode],
- rate->rate))
- continue;
- }
-
- rate->flags |= IEEE80211_RATE_SUPPORTED;
-
- /* Use configured basic rate set if it is available. If not,
- * use defaults that are sane for most cases. */
- if (local->basic_rates[mode->mode]) {
- if (rate_list_match(local->basic_rates[mode->mode],
- rate->rate))
- rate->flags |= IEEE80211_RATE_BASIC;
- } else switch (mode->mode) {
- case MODE_IEEE80211A:
- if (rate->rate == 60 || rate->rate == 120 ||
- rate->rate == 240)
- rate->flags |= IEEE80211_RATE_BASIC;
- break;
- case MODE_IEEE80211B:
- if (rate->rate == 10 || rate->rate == 20)
- rate->flags |= IEEE80211_RATE_BASIC;
- break;
- case MODE_IEEE80211G:
- if (rate->rate == 10 || rate->rate == 20 ||
- rate->rate == 55 || rate->rate == 110)
- rate->flags |= IEEE80211_RATE_BASIC;
- break;
- case NUM_IEEE80211_MODES:
- /* not useful */
- break;
- }
-
- /* Set ERP and MANDATORY flags based on phymode */
- switch (mode->mode) {
- case MODE_IEEE80211A:
- if (rate->rate == 60 || rate->rate == 120 ||
- rate->rate == 240)
- rate->flags |= IEEE80211_RATE_MANDATORY;
- break;
- case MODE_IEEE80211B:
- if (rate->rate == 10)
- rate->flags |= IEEE80211_RATE_MANDATORY;
- break;
- case MODE_IEEE80211G:
- if (rate->rate == 10 || rate->rate == 20 ||
- rate->rate == 55 || rate->rate == 110 ||
- rate->rate == 60 || rate->rate == 120 ||
- rate->rate == 240)
- rate->flags |= IEEE80211_RATE_MANDATORY;
- break;
- case NUM_IEEE80211_MODES:
- /* not useful */
- break;
- }
- if (ieee80211_is_erp_rate(mode->mode, rate->rate))
- rate->flags |= IEEE80211_RATE_ERP;
- }
-}
-
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
enum ieee80211_if_types type)
{
}
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
-void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
+int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
+{
+ int ae = meshhdr->flags & IEEE80211S_FLAGS_AE;
+ /* 7.1.3.5a.2 */
+ switch (ae) {
+ case 0:
+ return 5;
+ case 1:
+ return 11;
+ case 2:
+ return 17;
+ case 3:
+ return 23;
+ default:
+ return 5;
+ }
+}
+
+void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- if (tx->u.tx.extra_frag) {
+ if (tx->extra_frag) {
struct ieee80211_hdr *fhdr;
int i;
- for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ for (i = 0; i < tx->num_extra_frag; i++) {
fhdr = (struct ieee80211_hdr *)
- tx->u.tx.extra_frag[i]->data;
+ tx->extra_frag[i]->data;
fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
}
}
* DIV_ROUND_UP() operations.
*/
- if (local->hw.conf.phymode == MODE_IEEE80211A || erp) {
+ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
/*
* OFDM:
*
/* Exported duration function for driver use */
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- size_t frame_len, int rate)
+ size_t frame_len,
+ struct ieee80211_rate *rate)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
u16 dur;
int erp;
- erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
- dur = ieee80211_frame_duration(local, frame_len, rate, erp,
+ erp = 0;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
+
+ dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
sdata->bss_conf.use_short_preamble);
return cpu_to_le16(dur);
short_preamble = sdata->bss_conf.use_short_preamble;
- rate = frame_txctl->rts_rate;
- erp = !!(rate->flags & IEEE80211_RATE_ERP);
+ rate = frame_txctl->rts_cts_rate;
+
+ erp = 0;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
/* CTS duration */
- dur = ieee80211_frame_duration(local, 10, rate->rate,
+ dur = ieee80211_frame_duration(local, 10, rate->bitrate,
erp, short_preamble);
/* Data frame duration */
- dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+ dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
erp, short_preamble);
/* ACK duration */
- dur += ieee80211_frame_duration(local, 10, rate->rate,
+ dur += ieee80211_frame_duration(local, 10, rate->bitrate,
erp, short_preamble);
return cpu_to_le16(dur);
short_preamble = sdata->bss_conf.use_short_preamble;
- rate = frame_txctl->rts_rate;
- erp = !!(rate->flags & IEEE80211_RATE_ERP);
+ rate = frame_txctl->rts_cts_rate;
+ erp = 0;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
/* Data frame duration */
- dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+ dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
erp, short_preamble);
if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
/* ACK duration */
- dur += ieee80211_frame_duration(local, 10, rate->rate,
+ dur += ieee80211_frame_duration(local, 10, rate->bitrate,
erp, short_preamble);
}
}
EXPORT_SYMBOL(ieee80211_ctstoself_duration);
-struct ieee80211_rate *
-ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
-{
- struct ieee80211_hw_mode *mode;
- int r;
-
- list_for_each_entry(mode, &local->modes_list, list) {
- if (mode->mode != phymode)
- continue;
- for (r = 0; r < mode->num_rates; r++) {
- struct ieee80211_rate *rate = &mode->rates[r];
- if (rate->val == hw_rate ||
- (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
- rate->val2 == hw_rate))
- return rate;
- }
- }
-
- return NULL;
-}
-
void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
{
struct ieee80211_local *local = hw_to_local(hw);
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
case IEEE80211_IF_TYPE_WDS:
+ case IEEE80211_IF_TYPE_MESH_POINT:
break;
}
if (sdata->dev == local->mdev)
return NULL;
}
-ieee80211_txrx_result
-ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_rx_result
+ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
{
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
(rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
- if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
+ if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
"failed\n", rx->dev->name);
#endif /* CONFIG_MAC80211_DEBUG */
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
- } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
+ } else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) {
ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
/* remove ICV */
skb_trim(rx->skb, rx->skb->len - 4);
}
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
-static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
+static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
{
if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
return -1;
} else {
- tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
+ tx->control->key_idx = tx->key->conf.hw_key_idx;
if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
return -1;
return 0;
}
-ieee80211_txrx_result
-ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
+ieee80211_tx_result
+ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
{
- tx->u.tx.control->iv_len = WEP_IV_LEN;
- tx->u.tx.control->icv_len = WEP_ICV_LEN;
- ieee80211_tx_set_iswep(tx);
+ tx->control->iv_len = WEP_IV_LEN;
+ tx->control->icv_len = WEP_ICV_LEN;
+ ieee80211_tx_set_protected(tx);
if (wep_encrypt_skb(tx, tx->skb) < 0) {
I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
- return TXRX_DROP;
+ return TX_DROP;
}
- if (tx->u.tx.extra_frag) {
+ if (tx->extra_frag) {
int i;
- for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
- if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) {
+ for (i = 0; i < tx->num_extra_frag; i++) {
+ if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) {
I802_DEBUG_INC(tx->local->
tx_handlers_drop_wep);
- return TXRX_DROP;
+ return TX_DROP;
}
}
}
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
struct ieee80211_key *key);
u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
-ieee80211_txrx_result
-ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx);
-ieee80211_txrx_result
-ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx);
+ieee80211_tx_result
+ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx);
#endif /* WEP_H */
#include "wme.h"
/* maximum number of hardware queues we support. */
-#define TC_80211_MAX_QUEUES 8
+#define TC_80211_MAX_QUEUES 16
+
+const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
struct ieee80211_sched_data
{
+ unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)];
struct tcf_proto *filter_list;
struct Qdisc *queues[TC_80211_MAX_QUEUES];
struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
unsigned short fc = le16_to_cpu(hdr->frame_control);
int qos;
- const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
/* see if frame is data or non data frame */
if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
unsigned short fc = le16_to_cpu(hdr->frame_control);
struct Qdisc *qdisc;
int err, queue;
+ struct sta_info *sta;
+ u8 tid;
if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
- skb_queue_tail(&q->requeued[pkt_data->queue], skb);
+ queue = pkt_data->queue;
+ rcu_read_lock();
+ sta = sta_info_get(local, hdr->addr1);
+ tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
+ if (sta) {
+ int ampdu_queue = sta->tid_to_tx_q[tid];
+ if ((ampdu_queue < local->hw.queues) &&
+ test_bit(ampdu_queue, q->qdisc_pool)) {
+ queue = ampdu_queue;
+ pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+ } else {
+ pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+ }
+ }
+ rcu_read_unlock();
+ skb_queue_tail(&q->requeued[queue], skb);
qd->q.qlen++;
return 0;
}
*/
if (WLAN_FC_IS_QOS_DATA(fc)) {
u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2;
- u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK;
+ u8 ack_policy = 0;
+ tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
if (local->wifi_wme_noack_test)
- qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK <<
+ ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
QOS_CONTROL_ACK_POLICY_SHIFT;
/* qos header is 2 bytes, second reserved */
- *p = qos_hdr;
+ *p = ack_policy | tid;
p++;
*p = 0;
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, hdr->addr1);
+ if (sta) {
+ int ampdu_queue = sta->tid_to_tx_q[tid];
+ if ((ampdu_queue < local->hw.queues) &&
+ test_bit(ampdu_queue, q->qdisc_pool)) {
+ queue = ampdu_queue;
+ pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+ } else {
+ pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+ }
+ }
+
+ rcu_read_unlock();
}
if (unlikely(queue >= local->hw.queues)) {
kfree_skb(skb);
err = NET_XMIT_DROP;
} else {
+ tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
pkt_data->queue = (unsigned int) queue;
qdisc = q->queues[queue];
err = qdisc->enqueue(skb, qdisc);
/* check all the h/w queues in numeric/priority order */
for (queue = 0; queue < hw->queues; queue++) {
/* see if there is room in this hardware queue */
- if (test_bit(IEEE80211_LINK_STATE_XOFF,
- &local->state[queue]) ||
- test_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[queue]))
+ if ((test_bit(IEEE80211_LINK_STATE_XOFF,
+ &local->state[queue])) ||
+ (test_bit(IEEE80211_LINK_STATE_PENDING,
+ &local->state[queue])) ||
+ (!test_bit(queue, q->qdisc_pool)))
continue;
/* there is space - try and get a frame */
}
}
+ /* reserve all legacy QoS queues */
+ for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
+ set_bit(i, q->qdisc_pool);
+
return err;
}
{
unregister_qdisc(&wme_qdisc_ops);
}
+
+int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tid)
+{
+ int i;
+ struct ieee80211_sched_data *q =
+ qdisc_priv(local->mdev->qdisc_sleeping);
+ DECLARE_MAC_BUF(mac);
+
+ /* prepare the filter and save it for the SW queue
+ * matching the recieved HW queue */
+
+ /* try to get a Qdisc from the pool */
+ for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
+ if (!test_and_set_bit(i, q->qdisc_pool)) {
+ ieee80211_stop_queue(local_to_hw(local), i);
+ sta->tid_to_tx_q[tid] = i;
+
+ /* IF there are already pending packets
+ * on this tid first we need to drain them
+ * on the previous queue
+ * since HT is strict in order */
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_DEBUG "allocated aggregation queue"
+ " %d tid %d addr %s pool=0x%lX",
+ i, tid, print_mac(mac, sta->addr),
+ q->qdisc_pool[0]);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ return 0;
+ }
+
+ return -EAGAIN;
+}
+
+/**
+ * the caller needs to hold local->mdev->queue_lock
+ */
+void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tid,
+ u8 requeue)
+{
+ struct ieee80211_sched_data *q =
+ qdisc_priv(local->mdev->qdisc_sleeping);
+ int agg_queue = sta->tid_to_tx_q[tid];
+
+ /* return the qdisc to the pool */
+ clear_bit(agg_queue, q->qdisc_pool);
+ sta->tid_to_tx_q[tid] = local->hw.queues;
+
+ if (requeue)
+ ieee80211_requeue(local, agg_queue);
+ else
+ q->queues[agg_queue]->ops->reset(q->queues[agg_queue]);
+}
+
+void ieee80211_requeue(struct ieee80211_local *local, int queue)
+{
+ struct Qdisc *root_qd = local->mdev->qdisc_sleeping;
+ struct ieee80211_sched_data *q = qdisc_priv(root_qd);
+ struct Qdisc *qdisc = q->queues[queue];
+ struct sk_buff *skb = NULL;
+ u32 len = qdisc->q.qlen;
+
+ if (!qdisc || !qdisc->dequeue)
+ return;
+
+ printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen);
+ for (len = qdisc->q.qlen; len > 0; len--) {
+ skb = qdisc->dequeue(qdisc);
+ root_qd->q.qlen--;
+ /* packet will be classified again and */
+ /* skb->packet_data->queue will be overridden if needed */
+ if (skb)
+ wme_qdiscop_enqueue(skb, root_qd);
+ }
+}
#define QOS_CONTROL_TAG1D_MASK 0x07
+extern const int ieee802_1d_to_ac[8];
+
static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
{
return (fc & 0x8C) == 0x88;
#ifdef CONFIG_NET_SCHED
void ieee80211_install_qdisc(struct net_device *dev);
int ieee80211_qdisc_installed(struct net_device *dev);
-
+int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tid);
+void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tid,
+ u8 requeue);
+void ieee80211_requeue(struct ieee80211_local *local, int queue);
int ieee80211_wme_register(void);
void ieee80211_wme_unregister(void);
#else
{
return 0;
}
-
+static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tid)
+{
+ return -EAGAIN;
+}
+static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tid,
+ u8 requeue)
+{
+}
+static inline void ieee80211_requeue(struct ieee80211_local *local, int queue)
+{
+}
static inline int ieee80211_wme_register(void)
{
return 0;
}
-ieee80211_txrx_result
-ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
+ieee80211_tx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
{
u8 *data, *sa, *da, *key, *mic, qos_tid;
size_t data_len;
if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
!WLAN_FC_DATA_PRESENT(fc))
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
- return TXRX_DROP;
+ return TX_DROP;
if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
- !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) &&
+ !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
!(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) &&
!wpa_test) {
/* hwaccel - with no need for preallocated room for Michael MIC
*/
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
GFP_ATOMIC))) {
printk(KERN_DEBUG "%s: failed to allocate more memory "
"for Michael MIC\n", tx->dev->name);
- return TXRX_DROP;
+ return TX_DROP;
}
}
mic = skb_put(skb, MICHAEL_MIC_LEN);
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-ieee80211_txrx_result
-ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
+ieee80211_rx_result
+ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
{
u8 *data, *sa, *da, *key = NULL, qos_tid;
size_t data_len;
/*
* No way to verify the MIC if the hardware stripped it
*/
- if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED)
- return TXRX_CONTINUE;
+ if (rx->status->flag & RX_FLAG_MMIC_STRIPPED)
+ return RX_CONTINUE;
if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
!(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
|| data_len < MICHAEL_MIC_LEN)
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
data_len -= MICHAEL_MIC_LEN;
ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
- if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
- return TXRX_DROP;
+ if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ return RX_DROP_UNUSABLE;
printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
"%s\n", rx->dev->name, print_mac(mac, sa));
mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
(void *) skb->data);
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
/* remove Michael MIC from payload */
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
/* update IV in key information to be able to detect replays */
- rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32;
- rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16;
+ rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32;
+ rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16;
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
-static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
+static int tkip_encrypt_skb(struct ieee80211_tx_data *tx,
struct sk_buff *skb, int test)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
0x7f),
(u8) key->u.tkip.iv16);
- tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
+ tx->control->key_idx = tx->key->conf.hw_key_idx;
return 0;
}
}
-ieee80211_txrx_result
-ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
+ieee80211_tx_result
+ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb = tx->skb;
int wpa_test = 0, test = 0;
- tx->u.tx.control->icv_len = TKIP_ICV_LEN;
- tx->u.tx.control->iv_len = TKIP_IV_LEN;
- ieee80211_tx_set_iswep(tx);
+ tx->control->icv_len = TKIP_ICV_LEN;
+ tx->control->iv_len = TKIP_IV_LEN;
+ ieee80211_tx_set_protected(tx);
if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
!(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
!wpa_test) {
/* hwaccel - with no need for preallocated room for IV/ICV */
- tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
- return TXRX_CONTINUE;
+ tx->control->key_idx = tx->key->conf.hw_key_idx;
+ return TX_CONTINUE;
}
if (tkip_encrypt_skb(tx, skb, test) < 0)
- return TXRX_DROP;
+ return TX_DROP;
- if (tx->u.tx.extra_frag) {
+ if (tx->extra_frag) {
int i;
- for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
- if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
+ for (i = 0; i < tx->num_extra_frag; i++) {
+ if (tkip_encrypt_skb(tx, tx->extra_frag[i], test)
< 0)
- return TXRX_DROP;
+ return TX_DROP;
}
}
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-ieee80211_txrx_result
-ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_rx_result
+ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
u16 fc;
hdrlen = ieee80211_get_hdrlen(fc);
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
if (!rx->sta || skb->len - hdrlen < 12)
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
- if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) {
- if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) {
+ if (rx->status->flag & RX_FLAG_DECRYPTED) {
+ if (rx->status->flag & RX_FLAG_IV_STRIPPED) {
/*
* Hardware took care of all processing, including
* replay protection, and stripped the ICV/IV so
* we cannot do any checks here.
*/
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
/* let TKIP code verify IV, but skip decryption */
res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
key, skb->data + hdrlen,
skb->len - hdrlen, rx->sta->addr,
- hwaccel, rx->u.rx.queue,
- &rx->u.rx.tkip_iv32,
- &rx->u.rx.tkip_iv16);
+ hwaccel, rx->queue,
+ &rx->tkip_iv32,
+ &rx->tkip_iv16);
if (res != TKIP_DECRYPT_OK || wpa_test) {
#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
"frame from %s (res=%d)\n", rx->dev->name,
print_mac(mac, rx->sta->addr), res);
#endif /* CONFIG_MAC80211_DEBUG */
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
/* Trim ICV */
memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
skb_pull(skb, TKIP_IV_LEN);
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
}
-static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
+static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
struct sk_buff *skb, int test)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
/* hwaccel - with preallocated room for CCMP header */
- tx->u.tx.control->key_idx = key->conf.hw_key_idx;
+ tx->control->key_idx = key->conf.hw_key_idx;
return 0;
}
}
-ieee80211_txrx_result
-ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
+ieee80211_tx_result
+ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb = tx->skb;
int test = 0;
- tx->u.tx.control->icv_len = CCMP_MIC_LEN;
- tx->u.tx.control->iv_len = CCMP_HDR_LEN;
- ieee80211_tx_set_iswep(tx);
+ tx->control->icv_len = CCMP_MIC_LEN;
+ tx->control->iv_len = CCMP_HDR_LEN;
+ ieee80211_tx_set_protected(tx);
if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
!(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
/* hwaccel - with no need for preallocated room for CCMP "
* header or MIC fields */
- tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
- return TXRX_CONTINUE;
+ tx->control->key_idx = tx->key->conf.hw_key_idx;
+ return TX_CONTINUE;
}
if (ccmp_encrypt_skb(tx, skb, test) < 0)
- return TXRX_DROP;
+ return TX_DROP;
- if (tx->u.tx.extra_frag) {
+ if (tx->extra_frag) {
int i;
- for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
- if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
+ for (i = 0; i < tx->num_extra_frag; i++) {
+ if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test)
< 0)
- return TXRX_DROP;
+ return TX_DROP;
}
}
- return TXRX_CONTINUE;
+ return TX_CONTINUE;
}
-ieee80211_txrx_result
-ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_rx_result
+ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
u16 fc;
hdrlen = ieee80211_get_hdrlen(fc);
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
if (!rx->sta || data_len < 0)
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
- if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
- (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
- return TXRX_CONTINUE;
+ if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
+ (rx->status->flag & RX_FLAG_IV_STRIPPED))
+ return RX_CONTINUE;
(void) ccmp_hdr2pn(pn, skb->data + hdrlen);
- if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) {
+ if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) {
#ifdef CONFIG_MAC80211_DEBUG
- u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue];
+ u8 *ppn = key->u.ccmp.rx_pn[rx->queue];
printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from "
"%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]);
#endif /* CONFIG_MAC80211_DEBUG */
key->u.ccmp.replays++;
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
- if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
+ if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
/* hardware didn't decrypt/verify MIC */
u8 *scratch, *b_0, *aad;
"for RX frame from %s\n", rx->dev->name,
print_mac(mac, rx->sta->addr));
#endif /* CONFIG_MAC80211_DEBUG */
- return TXRX_DROP;
+ return RX_DROP_UNUSABLE;
}
}
- memcpy(key->u.ccmp.rx_pn[rx->u.rx.queue], pn, CCMP_PN_LEN);
+ memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN);
/* Remove CCMP header and MIC */
skb_trim(skb, skb->len - CCMP_MIC_LEN);
memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
skb_pull(skb, CCMP_HDR_LEN);
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
#include <linux/types.h>
#include "ieee80211_i.h"
-ieee80211_txrx_result
-ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
-ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx);
+ieee80211_tx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx);
-ieee80211_txrx_result
-ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
-ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx);
+ieee80211_tx_result
+ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx);
-ieee80211_txrx_result
-ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
-ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx);
+ieee80211_tx_result
+ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx);
#endif /* WPA_H */
{
struct nf_conntrack_expect *exp;
struct iphdr *iph = ip_hdr(skb);
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
struct in_device *in_dev;
__be32 mask = 0;
.open = ct_cpu_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release,
};
#endif /* CONFIG_PROC_FS */
* queueing.
*/
-static void __netlink_release(struct sock *sk)
-{
- /*
- * Last sock_put should drop referrence to sk->sk_net. It has already
- * been dropped in netlink_kernel_create. Taking referrence to stopping
- * namespace is not an option.
- * Take referrence to a socket to remove it from netlink lookup table
- * _alive_ and after that destroy it in the context of init_net.
- */
-
- sock_hold(sk);
- sock_release(sk->sk_socket);
- sk->sk_net = get_net(&init_net);
- sock_put(sk);
-}
-
struct sock *
netlink_kernel_create(struct net *net, int unit, unsigned int groups,
void (*input)(struct sk_buff *skb),
goto out_sock_release_nosk;
sk = sock->sk;
- put_net(sk->sk_net);
- sk->sk_net = net;
+ sk_change_net(sk, net);
if (groups < 32)
groups = 32;
out_sock_release:
kfree(listeners);
- __netlink_release(sk);
+ netlink_kernel_release(sk);
return NULL;
out_sock_release_nosk:
void
netlink_kernel_release(struct sock *sk)
{
- if (sk == NULL || sk->sk_socket == NULL)
- return;
-
- __netlink_release(sk);
+ sk_release_kernel(sk);
}
EXPORT_SYMBOL(netlink_kernel_release);
{
}
-#define kenter(FMT,...) dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
-#define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define kenter(FMT,...) dbgprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
+#define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
#define kdebug(FMT,...) dbgprintk(" "FMT ,##__VA_ARGS__)
#define kproto(FMT,...) dbgprintk("### "FMT ,##__VA_ARGS__)
#define knet(FMT,...) dbgprintk("@@@ "FMT ,##__VA_ARGS__)
} while (0)
#else
-#define _enter(FMT,...) _dbprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
-#define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define _enter(FMT,...) _dbprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
+#define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
#define _debug(FMT,...) _dbprintk(" "FMT ,##__VA_ARGS__)
#define _proto(FMT,...) _dbprintk("### "FMT ,##__VA_ARGS__)
#define _net(FMT,...) _dbprintk("@@@ "FMT ,##__VA_ARGS__)
.open = rxrpc_call_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release,
};
/*
.open = rxrpc_connection_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release,
};
META_COLLECTOR(int_rtiif)
{
- if (unlikely(skb->dst == NULL))
+ if (unlikely(skb->rtable == NULL))
*err = -1;
else
- dst->value = ((struct rtable*) skb->dst)->fl.iif;
+ dst->value = skb->rtable->fl.iif;
}
/**************************************************************************
}
SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
- __FUNCTION__, asoc, asoc->pathmtu, asoc->frag_point);
+ __func__, asoc, asoc->pathmtu, asoc->frag_point);
}
/* Should we send a SACK to update our peer? */
}
SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) "
- "- %u\n", __FUNCTION__, asoc, len, asoc->rwnd,
+ "- %u\n", __func__, asoc, len, asoc->rwnd,
asoc->rwnd_over, asoc->a_rwnd);
/* Send a window update SACK if the rwnd has increased by at least the
if (sctp_peer_needs_update(asoc)) {
asoc->a_rwnd = asoc->rwnd;
SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p "
- "rwnd: %u a_rwnd: %u\n", __FUNCTION__,
+ "rwnd: %u a_rwnd: %u\n", __func__,
asoc, asoc->rwnd, asoc->a_rwnd);
sack = sctp_make_sack(asoc);
if (!sack)
asoc->rwnd = 0;
}
SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n",
- __FUNCTION__, asoc, len, asoc->rwnd,
+ __func__, asoc, len, asoc->rwnd,
asoc->rwnd_over);
}
msecs_to_jiffies(sinfo->sinfo_timetolive);
msg->can_abandon = 1;
SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
- __FUNCTION__, msg, msg->expires_at, jiffies);
+ __func__, msg, msg->expires_at, jiffies);
}
max = asoc->frag_point;
struct sctp_association *asoc,
struct sctp_transport *t)
{
- SCTP_DEBUG_PRINTK("%s\n", __FUNCTION__);
+ SCTP_DEBUG_PRINTK("%s\n", __func__);
sctp_do_sm(SCTP_EVENT_T_OTHER,
SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
"src:" NIP6_FMT " dst:" NIP6_FMT "\n",
- __FUNCTION__, skb, skb->len,
+ __func__, skb, skb->len,
NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
- __FUNCTION__, NIP6(fl.fl6_dst));
+ __func__, NIP6(fl.fl6_dst));
if (saddr) {
ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
NIP6(fl.fl6_src));
}
- dst = ip6_route_output(NULL, &fl);
+ dst = ip6_route_output(&init_net, NULL, &fl);
if (!dst->error) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
"daddr:" NIP6_FMT " ",
- __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
+ __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
if (!asoc) {
- ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
+ ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+ &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
NIP6(saddr->v6.sin6_addr));
return;
} else {
printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
"address for the dest:" NIP6_FMT "\n",
- __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
+ __func__, asoc, NIP6(daddr->v6.sin6_addr));
}
rcu_read_unlock();
{
struct sctp_chunk *chunk = NULL;
- SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __FUNCTION__,
+ SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__,
packet, vtag);
packet->vtag = vtag;
struct sctp_association *asoc = transport->asoc;
size_t overhead;
- SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __FUNCTION__,
+ SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __func__,
packet, transport);
packet->transport = transport;
{
struct sctp_chunk *chunk, *tmp;
- SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
+ SCTP_DEBUG_PRINTK("%s: packet:%p\n", __func__, packet);
list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
list_del_init(&chunk->list);
sctp_xmit_t retval;
int error = 0;
- SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__,
+ SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__,
packet, chunk);
switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) {
size_t pmtu;
int too_big;
- SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet,
+ SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet,
chunk);
/* Try to bundle AUTH chunk */
unsigned char *auth = NULL; /* pointer to auth in skb data */
__u32 cksum_buf_len = sizeof(struct sctphdr);
- SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
+ SCTP_DEBUG_PRINTK("%s: packet:%p\n", __func__, packet);
/* Do NOT generate a chunkless packet. */
if (list_empty(&packet->chunk_list))
"transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, "
"pba: %d\n",
- __FUNCTION__, transport,
+ __func__, transport,
transport->cwnd,
transport->ssthresh,
transport->flight_size,
SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, "
"cwnd: %d, ssthresh: %d, flight_size: %d, "
- "pba: %d\n", __FUNCTION__,
+ "pba: %d\n", __func__,
transport, reason,
transport->cwnd, transport->ssthresh,
transport->flight_size,
*/
if (transport == transport->asoc->peer.retran_path)
sctp_assoc_update_retran_path(transport->asoc);
+ transport->asoc->rtx_data_chunks +=
+ transport->asoc->unack_data;
break;
case SCTP_RTXR_FAST_RTX:
SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
break;
case SCTP_RTXR_T1_RTX:
SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS);
+ transport->asoc->init_retries++;
break;
default:
BUG();
sctp_generate_fwdtsn(q, sack_ctsn);
SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",
- __FUNCTION__, sack_ctsn);
+ __func__, sack_ctsn);
SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, "
"%p is 0x%x. Adv peer ack point: 0x%x\n",
- __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point);
+ __func__, asoc, ctsn, asoc->adv_peer_ack_point);
/* See if all chunks are acked.
* Make sure the empty queue handler will get run later.
if (tchunk->tsn_gap_acked) {
SCTP_DEBUG_PRINTK("%s: Receiver reneged on "
"data TSN: 0x%x\n",
- __FUNCTION__,
+ __func__,
tsn);
tchunk->tsn_gap_acked = 0;
(sack_ctsn+2 == q->asoc->next_tsn)) {
SCTP_DEBUG_PRINTK("%s: SACK received for zero "
"window probe: %u\n",
- __FUNCTION__, sack_ctsn);
+ __func__, sack_ctsn);
q->asoc->overall_error_count = 0;
transport->error_count = 0;
}
SCTP_DEBUG_PRINTK(
"%s: TSN 0x%x missing counter: %d\n",
- __FUNCTION__, tsn,
+ __func__, tsn,
chunk->tsn_missing_report);
}
}
SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d\n",
- __FUNCTION__, transport, transport->cwnd,
+ __func__, transport, transport->cwnd,
transport->ssthresh, transport->flight_size,
transport->partial_bytes_acked);
}
*pos = 0;
if (*pos == 0)
- seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
- "RPORT LADDRS <-> RADDRS\n");
+ seq_printf(seq, " ASSOC SOCK STY SST ST HBKT "
+ "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
+ "RPORT LADDRS <-> RADDRS "
+ "HBINT INS OUTS MAXRT T1X T2X RTXC\n");
return (void *)pos;
}
assoc = sctp_assoc(epb);
sk = epb->sk;
seq_printf(seq,
- "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
+ "%8p %8p %-3d %-3d %-2d %-4d "
+ "%4d %8d %8d %7d %5lu %-5d %5d "
+ "%8lu %5d %5d %4d %4d %4d %8d ",
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
- assoc->state, hash, assoc->assoc_id,
+ assoc->state, hash,
+ assoc->assoc_id,
assoc->sndbuf_used,
atomic_read(&assoc->rmem_alloc),
sock_i_uid(sk), sock_i_ino(sk),
epb->bind_addr.port,
- assoc->peer.port);
-
+ assoc->peer.port,
+ assoc->hbinterval, assoc->c.sinit_max_instreams,
+ assoc->c.sinit_num_ostreams, assoc->max_retrans,
+ assoc->init_retries, assoc->shutdown_retries,
+ assoc->rtx_data_chunks);
seq_printf(seq, " ");
sctp_seq_dump_local_addrs(seq, epb);
seq_printf(seq, "<-> ");
return 0;
/* Is this a broadcast address? */
- if (skb && ((struct rtable *)skb->dst)->rt_flags & RTCF_BROADCAST)
+ if (skb && skb->rtable->rt_flags & RTCF_BROADCAST)
return 0;
return 1;
fl.fl4_src = saddr->v4.sin_addr.s_addr;
SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ",
- __FUNCTION__, NIPQUAD(fl.fl4_dst),
+ __func__, NIPQUAD(fl.fl4_dst),
NIPQUAD(fl.fl4_src));
if (!ip_route_output_key(&init_net, &rt, &fl)) {
/* What interface did this skb arrive on? */
static int sctp_v4_skb_iif(const struct sk_buff *skb)
{
- return ((struct rtable *)skb->dst)->rt_iif;
+ return skb->rtable->rt_iif;
}
/* Was this packet marked by Explicit Congestion Notification? */
struct sctp_sockaddr_entry *temp;
int found = 0;
+ if (ifa->ifa_dev->dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
switch (ev) {
case NETDEV_UP:
addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
{
SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
"src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n",
- __FUNCTION__, skb, skb->len,
- NIPQUAD(((struct rtable *)skb->dst)->rt_src),
- NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
+ __func__, skb, skb->len,
+ NIPQUAD(skb->rtable->rt_src),
+ NIPQUAD(skb->rtable->rt_dst));
SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
return ip_queue_xmit(skb, ipfragok);
sctp_bh_lock_sock(asoc->base.sk);
if (sock_owned_by_user(asoc->base.sk)) {
- SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
+ SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
/* Try again later. */
if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20)))
sctp_bh_lock_sock(asoc->base.sk);
if (sock_owned_by_user(asoc->base.sk)) {
SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n",
- __FUNCTION__,
+ __func__,
timeout_type);
/* Try again later. */
sctp_bh_lock_sock(asoc->base.sk);
if (sock_owned_by_user(asoc->base.sk)) {
- SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
+ SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
/* Try again later. */
if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20)))
printk(KERN_WARNING
"%s association %p could not find address "
NIP6_FMT "\n",
- __FUNCTION__,
+ __func__,
asoc,
NIP6(from_addr.v6.sin6_addr));
} else {
printk(KERN_WARNING
"%s association %p could not find address "
NIPQUAD_FMT "\n",
- __FUNCTION__,
+ __func__,
asoc,
NIPQUAD(from_addr.v4.sin_addr.s_addr));
}
time_after(jiffies, hbinfo->sent_at + max_interval)) {
SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp "
"received for transport: %p\n",
- __FUNCTION__, link);
+ __func__, link);
return SCTP_DISPOSITION_DISCARD;
}
skb_pull(chunk->skb, len);
tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
- SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+ SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn);
/* The TSN is too high--silently discard the chunk and count on it
* getting retransmitted later.
skb_pull(chunk->skb, len);
tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
- SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+ SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn);
/* The TSN is too high--silently discard the chunk and count on it
* getting retransmitted later.
SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS);
+ ((struct sctp_association *)asoc)->shutdown_retries++;
+
if (asoc->overall_error_count >= asoc->max_retrans) {
sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
SCTP_ERROR(ETIMEDOUT));
ep = sp->ep;
SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
- __FUNCTION__, sk, addrs, addrcnt);
+ __func__, sk, addrs, addrcnt);
list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs);
ep = sp->ep;
SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
- __FUNCTION__, sk, addrs, addrcnt);
+ __func__, sk, addrs, addrcnt);
list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs);
struct sockaddr *kaddrs;
SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n",
- __FUNCTION__, sk, addrs, addrs_size);
+ __func__, sk, addrs, addrs_size);
if (unlikely(addrs_size <= 0))
return -EINVAL;
sctp_lock_sock(sk);
SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d\n",
- __FUNCTION__, sk, addr, addr_len);
+ __func__, sk, addr, addr_len);
/* Validate addr_len before calling common connect/connectx routine. */
af = sctp_get_af_specific(addr->sa_family);
goto out;
}
- SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc);
+ SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc);
retval = sctp_do_peeloff(asoc, &newsock);
if (retval < 0)
}
SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n",
- __FUNCTION__, sk, asoc, newsock->sk, retval);
+ __func__, sk, asoc, newsock->sk, retval);
/* Return the fd mapped to the new socket. */
peeloff.sd = retval;
long current_timeo = *timeo_p;
DEFINE_WAIT(wait);
- SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc,
+ SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __func__, asoc,
(long)(*timeo_p));
/* Increment the association's refcnt. */
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
printk(KERN_WARNING "%s: Reported pmtu %d too low, "
"using default minimum of %d\n",
- __FUNCTION__, pmtu,
+ __func__, pmtu,
SCTP_DEFAULT_MINSEGMENT);
/* Use default minimum segment size and disable
* pmtu discovery on this transport.
tp->rto_pending = 0;
SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d "
- "rttvar: %d, rto: %ld\n", __FUNCTION__,
+ "rttvar: %d, rto: %ld\n", __func__,
tp, rtt, tp->srtt, tp->rttvar, tp->rto);
}
SCTP_DEBUG_PRINTK("%s: SLOW START: transport: %p, "
"bytes_acked: %d, cwnd: %d, ssthresh: %d, "
"flight_size: %d, pba: %d\n",
- __FUNCTION__,
+ __func__,
transport, bytes_acked, cwnd,
ssthresh, flight_size, pba);
} else {
SCTP_DEBUG_PRINTK("%s: CONGESTION AVOIDANCE: "
"transport: %p, bytes_acked: %d, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d\n",
- __FUNCTION__,
+ __func__,
transport, bytes_acked, cwnd,
ssthresh, flight_size, pba);
}
transport->partial_bytes_acked = 0;
SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: "
- "%d ssthresh: %d\n", __FUNCTION__,
+ "%d ssthresh: %d\n", __func__,
transport, reason,
transport->cwnd, transport->ssthresh);
}
gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
if (!gss_auth->mech) {
printk(KERN_WARNING "%s: Pseudoflavor %d not found!\n",
- __FUNCTION__, flavor);
+ __func__, flavor);
goto err_free;
}
gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
#define dprint_status(t) \
dprintk("RPC: %5u %s (status %d)\n", t->tk_pid, \
- __FUNCTION__, t->tk_status)
+ __func__, t->tk_status)
/*
* All RPC clients are linked into this list
out_no_stats:
kfree(new);
out_no_clnt:
- dprintk("RPC: %s: returned error %d\n", __FUNCTION__, err);
+ dprintk("RPC: %s: returned error %d\n", __func__, err);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(rpc_clone_client);
}
printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n",
- __FUNCTION__, status);
+ __func__, status);
rpc_exit(task, -EIO);
return;
}
*/
if (task->tk_rqstp) {
printk(KERN_ERR "%s: status=%d, request allocated anyway\n",
- __FUNCTION__, status);
+ __func__, status);
xprt_release(task);
}
break;
default:
printk(KERN_ERR "%s: unrecognized error %d, exiting\n",
- __FUNCTION__, status);
+ __func__, status);
break;
}
rpc_exit(task, status);
* undefined results
*/
dprintk("RPC: %5u %s: XDR representation not a multiple of"
- " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__,
+ " 4 bytes: 0x%x\n", task->tk_pid, __func__,
task->tk_rqstp->rq_rcv_buf.len);
goto out_eio;
}
if ((n = ntohl(*p++)) != RPC_REPLY) {
dprintk("RPC: %5u %s: not an RPC reply: %x\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
goto out_garbage;
}
if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
case RPC_MISMATCH:
dprintk("RPC: %5u %s: RPC call version "
"mismatch!\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
error = -EPROTONOSUPPORT;
goto out_err;
default:
dprintk("RPC: %5u %s: RPC call rejected, "
"unknown error: %x\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
goto out_eio;
}
if (--len < 0)
break;
task->tk_cred_retry--;
dprintk("RPC: %5u %s: retry stale creds\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
rpcauth_invalcred(task);
/* Ensure we obtain a new XID! */
xprt_release(task);
break;
task->tk_garb_retry--;
dprintk("RPC: %5u %s: retry garbled creds\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
task->tk_action = call_bind;
goto out_retry;
case RPC_AUTH_TOOWEAK:
break;
default:
dprintk("RPC: %5u %s: unknown auth error: %x\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
error = -EIO;
}
dprintk("RPC: %5u %s: call rejected %d\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
goto out_err;
}
if (!(p = rpcauth_checkverf(task, p))) {
dprintk("RPC: %5u %s: auth check failed\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto out_garbage; /* bad verifier, retry */
}
len = p - (__be32 *)iov->iov_base - 1;
return p;
case RPC_PROG_UNAVAIL:
dprintk("RPC: %5u %s: program %u is unsupported by server %s\n",
- task->tk_pid, __FUNCTION__,
+ task->tk_pid, __func__,
(unsigned int)task->tk_client->cl_prog,
task->tk_client->cl_server);
error = -EPFNOSUPPORT;
goto out_err;
case RPC_PROG_MISMATCH:
dprintk("RPC: %5u %s: program %u, version %u unsupported by "
- "server %s\n", task->tk_pid, __FUNCTION__,
+ "server %s\n", task->tk_pid, __func__,
(unsigned int)task->tk_client->cl_prog,
(unsigned int)task->tk_client->cl_vers,
task->tk_client->cl_server);
case RPC_PROC_UNAVAIL:
dprintk("RPC: %5u %s: proc %p unsupported by program %u, "
"version %u on server %s\n",
- task->tk_pid, __FUNCTION__,
+ task->tk_pid, __func__,
task->tk_msg.rpc_proc,
task->tk_client->cl_prog,
task->tk_client->cl_vers,
goto out_err;
case RPC_GARBAGE_ARGS:
dprintk("RPC: %5u %s: server saw garbage\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
break; /* retry */
default:
dprintk("RPC: %5u %s: server accept status: %x\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
/* Also retry */
}
if (task->tk_garb_retry) {
task->tk_garb_retry--;
dprintk("RPC: %5u %s: retrying\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
task->tk_action = call_bind;
out_retry:
return ERR_PTR(-EAGAIN);
out_err:
rpc_exit(task, error);
dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
- __FUNCTION__, error);
+ __func__, error);
return ERR_PTR(error);
out_overflow:
dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,
- __FUNCTION__);
+ __func__);
goto out_garbage;
}
mnt = rpc_get_mount();
if (IS_ERR(mnt)) {
printk(KERN_WARNING "%s: %s failed to mount "
- "pseudofilesystem \n", __FILE__, __FUNCTION__);
+ "pseudofilesystem \n", __FILE__, __func__);
return PTR_ERR(mnt);
}
if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) {
printk(KERN_WARNING "%s: %s failed to find path %s\n",
- __FILE__, __FUNCTION__, path);
+ __FILE__, __func__, path);
rpc_put_mount();
return -ENOENT;
}
out_bad:
mutex_unlock(&dir->i_mutex);
printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
- __FILE__, __FUNCTION__, parent->d_name.name);
+ __FILE__, __func__, parent->d_name.name);
return -ENOMEM;
}
return 0;
out_err:
printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
- __FILE__, __FUNCTION__, dentry->d_name.name);
+ __FILE__, __func__, dentry->d_name.name);
return -ENOMEM;
}
err_dput:
dput(dentry);
printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
- __FILE__, __FUNCTION__, path, error);
+ __FILE__, __func__, path, error);
dentry = ERR_PTR(error);
goto out;
}
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
- __FILE__, __FUNCTION__, parent->d_name.name, name,
+ __FILE__, __func__, parent->d_name.name, name,
-ENOMEM);
goto out;
}
int status;
dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
- __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+ __func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
sizeof(*sin), prot, 2, 0);
struct rpcb_info *info;
dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
- task->tk_pid, __FUNCTION__,
+ task->tk_pid, __func__,
clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
/* Autobind on cloned rpc clients is discouraged */
if (xprt_test_and_set_binding(xprt)) {
status = -EAGAIN; /* tell caller to check again */
dprintk("RPC: %5u %s: waiting for another binder\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nowake;
}
if (xprt_bound(xprt)) {
status = 0;
dprintk("RPC: %5u %s: already bound\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nofree;
}
default:
status = -EAFNOSUPPORT;
dprintk("RPC: %5u %s: bad address family\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nofree;
}
if (info[xprt->bind_index].rpc_proc == NULL) {
xprt->bind_index = 0;
status = -EPFNOSUPPORT;
dprintk("RPC: %5u %s: no more getport versions available\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nofree;
}
bind_version = info[xprt->bind_index].rpc_vers;
dprintk("RPC: %5u %s: trying rpcbind version %u\n",
- task->tk_pid, __FUNCTION__, bind_version);
+ task->tk_pid, __func__, bind_version);
rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
bind_version, 0);
if (IS_ERR(rpcb_clnt)) {
status = PTR_ERR(rpcb_clnt);
dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
- task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
+ task->tk_pid, __func__, PTR_ERR(rpcb_clnt));
goto bailout_nofree;
}
if (!map) {
status = -ENOMEM;
dprintk("RPC: %5u %s: no memory available\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nofree;
}
map->r_prog = clnt->cl_prog;
if (IS_ERR(child)) {
status = -EIO;
dprintk("RPC: %5u %s: rpc_run_task failed\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout;
}
rpc_put_task(child);
nloop++;
} while (err == -EADDRINUSE && nloop != 2);
dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n",
- __FUNCTION__, NIPQUAD(myaddr.sin_addr),
+ __func__, NIPQUAD(myaddr.sin_addr),
port, err ? "failed" : "ok", err);
return err;
}
#include "subscr.h"
#include "config.h"
-int tipc_eth_media_start(void);
-void tipc_eth_media_stop(void);
-int tipc_handler_start(void);
-void tipc_handler_stop(void);
-int tipc_socket_init(void);
-void tipc_socket_stop(void);
-int tipc_netlink_start(void);
-void tipc_netlink_stop(void);
-#define TIPC_MOD_VER "1.6.2"
+#define TIPC_MOD_VER "1.6.3"
#ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3
/* TIPC API for external APIs (see tipc_port.h) */
EXPORT_SYMBOL(tipc_createport_raw);
-EXPORT_SYMBOL(tipc_set_msg_option);
EXPORT_SYMBOL(tipc_reject_msg);
EXPORT_SYMBOL(tipc_send_buf_fast);
EXPORT_SYMBOL(tipc_acknowledge);
extern void tipc_core_stop(void);
extern int tipc_core_start_net(void);
extern void tipc_core_stop_net(void);
+extern int tipc_handler_start(void);
+extern void tipc_handler_stop(void);
+extern int tipc_netlink_start(void);
+extern void tipc_netlink_stop(void);
+extern int tipc_socket_init(void);
+extern void tipc_socket_stop(void);
static inline int delimit(int val, int min, int max)
{
void tipc_link_set_queue_limits(struct link *l_ptr, u32 window)
{
/* Data messages from this node, inclusive FIRST_FRAGM */
- l_ptr->queue_limit[DATA_LOW] = window;
- l_ptr->queue_limit[DATA_MEDIUM] = (window / 3) * 4;
- l_ptr->queue_limit[DATA_HIGH] = (window / 3) * 5;
- l_ptr->queue_limit[DATA_CRITICAL] = (window / 3) * 6;
+ l_ptr->queue_limit[TIPC_LOW_IMPORTANCE] = window;
+ l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE] = (window / 3) * 4;
+ l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE] = (window / 3) * 5;
+ l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE] = (window / 3) * 6;
/* Transiting data messages,inclusive FIRST_FRAGM */
- l_ptr->queue_limit[DATA_LOW + 4] = 300;
- l_ptr->queue_limit[DATA_MEDIUM + 4] = 600;
- l_ptr->queue_limit[DATA_HIGH + 4] = 900;
- l_ptr->queue_limit[DATA_CRITICAL + 4] = 1200;
+ l_ptr->queue_limit[TIPC_LOW_IMPORTANCE + 4] = 300;
+ l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE + 4] = 600;
+ l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE + 4] = 900;
+ l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE + 4] = 1200;
l_ptr->queue_limit[CONN_MANAGER] = 1200;
l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200;
l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500;
tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg),
msg_fragm_no(msg));
break;
- case DATA_LOW:
- case DATA_MEDIUM:
- case DATA_HIGH:
- case DATA_CRITICAL:
+ case TIPC_LOW_IMPORTANCE:
+ case TIPC_MEDIUM_IMPORTANCE:
+ case TIPC_HIGH_IMPORTANCE:
+ case TIPC_CRITICAL_IMPORTANCE:
tipc_printf(buf, "DAT%u:", msg_user(msg));
if (msg_short(msg)) {
tipc_printf(buf, "CON:");
switch (usr) {
case CONN_MANAGER:
case NAME_DISTRIBUTOR:
- case DATA_LOW:
- case DATA_MEDIUM:
- case DATA_HIGH:
- case DATA_CRITICAL:
+ case TIPC_LOW_IMPORTANCE:
+ case TIPC_MEDIUM_IMPORTANCE:
+ case TIPC_HIGH_IMPORTANCE:
+ case TIPC_CRITICAL_IMPORTANCE:
if (msg_short(msg))
break; /* No error */
switch (msg_errcode(msg)) {
#include "core.h"
#define TIPC_VERSION 2
-#define DATA_LOW TIPC_LOW_IMPORTANCE
-#define DATA_MEDIUM TIPC_MEDIUM_IMPORTANCE
-#define DATA_HIGH TIPC_HIGH_IMPORTANCE
-#define DATA_CRITICAL TIPC_CRITICAL_IMPORTANCE
-#define SHORT_H_SIZE 24 /* Connected,in cluster */
+
+#define SHORT_H_SIZE 24 /* Connected, in-cluster messages */
#define DIR_MSG_H_SIZE 32 /* Directly addressed messages */
-#define CONN_MSG_H_SIZE 36 /* Routed connected msgs*/
-#define LONG_H_SIZE 40 /* Named Messages */
+#define LONG_H_SIZE 40 /* Named messages */
#define MCAST_H_SIZE 44 /* Multicast messages */
-#define MAX_H_SIZE 60 /* Inclusive full options */
+#define INT_H_SIZE 40 /* Internal messages */
+#define MIN_H_SIZE 24 /* Smallest legal TIPC header size */
+#define MAX_H_SIZE 60 /* Largest possible TIPC header size */
+
#define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE)
-#define LINK_CONFIG 13
/*
u32 pos, u32 mask, u32 val)
{
val = (val & mask) << pos;
- m->hdr[w] &= ~htonl(mask << pos);
- m->hdr[w] |= htonl(val);
+ val = htonl(val);
+ mask = htonl(mask << pos);
+ m->hdr[w] &= ~mask;
+ m->hdr[w] |= val;
}
/*
static inline void msg_set_version(struct tipc_msg *m)
{
- msg_set_bits(m, 0, 29, 0xf, TIPC_VERSION);
+ msg_set_bits(m, 0, 29, 7, TIPC_VERSION);
}
static inline u32 msg_user(struct tipc_msg *m)
static inline u32 msg_isdata(struct tipc_msg *m)
{
- return (msg_user(m) <= DATA_CRITICAL);
+ return (msg_user(m) <= TIPC_CRITICAL_IMPORTANCE);
}
static inline void msg_set_user(struct tipc_msg *m, u32 n)
msg_set_bits(m, 1, 19, 0x3, n);
}
-static inline void msg_set_options(struct tipc_msg *m, const char *opt, u32 sz)
-{
- u32 hsz = msg_hdr_sz(m);
- char *to = (char *)&m->hdr[hsz/4];
-
- if ((hsz < DIR_MSG_H_SIZE) || ((hsz + sz) > MAX_H_SIZE))
- return;
- msg_set_bits(m, 1, 16, 0x7, (hsz - 28)/4);
- msg_set_hdr_sz(m, hsz + sz);
- memcpy(to, opt, sz);
-}
-
static inline u32 msg_bcast_ack(struct tipc_msg *m)
{
return msg_bits(m, 1, 0, 0xffff);
return (struct tipc_msg *)msg_data(m);
}
-static inline void msg_expand(struct tipc_msg *m, u32 destnode)
-{
- if (!msg_short(m))
- return;
- msg_set_hdr_sz(m, LONG_H_SIZE);
- msg_set_orignode(m, msg_prevnode(m));
- msg_set_destnode(m, destnode);
- memset(&m->hdr[8], 0, 12);
-}
-
-
/*
TIPC internal message header format, version 2
#define NAME_DISTRIBUTOR 11
#define MSG_FRAGMENTER 12
#define LINK_CONFIG 13
-#define INT_H_SIZE 40
#define DSC_H_SIZE 40
/*
p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
p_ptr->publ.ref = ref;
msg = &p_ptr->publ.phdr;
- msg_init(msg, DATA_LOW, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, 0);
+ msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE,
+ 0);
msg_set_orignode(msg, tipc_own_addr);
msg_set_prevnode(msg, tipc_own_addr);
msg_set_origport(msg, ref);
return buf;
}
-int tipc_set_msg_option(struct tipc_port *tp_ptr, const char *opt, const u32 sz)
-{
- msg_expand(&tp_ptr->phdr, msg_destnode(&tp_ptr->phdr));
- msg_set_options(&tp_ptr->phdr, opt, sz);
- return TIPC_OK;
-}
-
int tipc_reject_msg(struct sk_buff *buf, u32 err)
{
struct tipc_msg *msg = buf_msg(buf);
msg_orignode(msg),
msg_destport(msg),
tipc_own_addr,
- DATA_HIGH,
+ TIPC_HIGH_IMPORTANCE,
TIPC_CONN_MSG,
err,
0,
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/string.h>
#include <asm/atomic.h>
#include <net/sock.h>
struct tipc_sock {
struct sock sk;
struct tipc_port *p;
- struct semaphore sem;
+ struct mutex lock;
};
#define tipc_sk(sk) ((struct tipc_sock*)sk)
tsock->p = port;
port->usr_handle = tsock;
- init_MUTEX(&tsock->sem);
+ mutex_init(&tsock->lock);
dbg("sock_create: %x\n",tsock);
dbg("sock_delete: %x\n",tsock);
if (!tsock)
return 0;
- down(&tsock->sem);
+ mutex_lock(&tsock->lock);
if (!sock->sk) {
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return 0;
}
atomic_dec(&tipc_queue_size);
}
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
sock_put(sk);
struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
int res;
- if (down_interruptible(&tsock->sem))
+ if (mutex_lock_interruptible(&tsock->lock))
return -ERESTARTSYS;
if (unlikely(!uaddr_len)) {
res = tipc_withdraw(tsock->p->ref, -addr->scope,
&addr->addr.nameseq);
exit:
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
u32 res;
- if (down_interruptible(&tsock->sem))
+ if (mutex_lock_interruptible(&tsock->lock))
return -ERESTARTSYS;
*uaddr_len = sizeof(*addr);
res = tipc_ownidentity(tsock->p->ref, &addr->addr.id);
addr->addr.name.domain = 0;
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
}
}
- if (down_interruptible(&tsock->sem))
+ if (mutex_lock_interruptible(&tsock->lock))
return -ERESTARTSYS;
if (needs_conn) {
}
if (likely(res != -ELINKCONG)) {
exit:
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
if (m->msg_flags & MSG_DONTWAIT) {
if (unlikely(dest))
return send_msg(iocb, sock, m, total_len);
- if (down_interruptible(&tsock->sem)) {
+ if (mutex_lock_interruptible(&tsock->lock)) {
return -ERESTARTSYS;
}
res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov);
if (likely(res != -ELINKCONG)) {
exit:
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
if (m->msg_flags & MSG_DONTWAIT) {
/* Look for a message in receive queue; wait if necessary */
- if (unlikely(down_interruptible(&tsock->sem)))
+ if (unlikely(mutex_lock_interruptible(&tsock->lock)))
return -ERESTARTSYS;
restart:
advance_queue(tsock);
}
exit:
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
/* Look for a message in receive queue; wait if necessary */
- if (unlikely(down_interruptible(&tsock->sem)))
+ if (unlikely(mutex_lock_interruptible(&tsock->lock)))
return -ERESTARTSYS;
restart:
goto restart;
exit:
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return sz_copied ? sz_copied : res;
}
return res;
}
- if (down_interruptible(&tsock->sem))
+ if (mutex_lock_interruptible(&tsock->lock))
return -ERESTARTSYS;
/* Wait for destination's 'ACK' response */
sock->state = SS_DISCONNECTING;
}
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
(flags & O_NONBLOCK)))
return -EWOULDBLOCK;
- if (down_interruptible(&tsock->sem))
+ if (mutex_lock_interruptible(&tsock->lock))
return -ERESTARTSYS;
if (wait_event_interruptible(*sock->sk->sk_sleep,
}
}
exit:
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
/**
* shutdown - shutdown socket connection
* @sock: socket structure
- * @how: direction to close (unused; always treated as read + write)
+ * @how: direction to close (must be SHUT_RDWR)
*
* Terminates connection (if necessary), then purges socket's receive queue.
*
struct sk_buff *buf;
int res;
- /* Could return -EINVAL for an invalid "how", but why bother? */
+ if (how != SHUT_RDWR)
+ return -EINVAL;
- if (down_interruptible(&tsock->sem))
+ if (mutex_lock_interruptible(&tsock->lock))
return -ERESTARTSYS;
sock_lock(tsock);
sock_unlock(tsock);
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
if ((res = get_user(value, (u32 __user *)ov)))
return res;
- if (down_interruptible(&tsock->sem))
+ if (mutex_lock_interruptible(&tsock->lock))
return -ERESTARTSYS;
switch (opt) {
res = -EINVAL;
}
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
if ((res = get_user(len, ol)))
return res;
- if (down_interruptible(&tsock->sem))
+ if (mutex_lock_interruptible(&tsock->lock))
return -ERESTARTSYS;
switch (opt) {
res = put_user(sizeof(value), ol);
}
- up(&tsock->sem);
+ mutex_unlock(&tsock->lock);
return res;
}
rc = proto_register(&unix_proto, 1);
if (rc != 0) {
printk(KERN_CRIT "%s: Cannot create unix_sock SLAB cache!\n",
- __FUNCTION__);
+ __func__);
goto out;
}
obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_CFG80211) += cfg80211.o
-cfg80211-y += core.o sysfs.o radiotap.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
cfg80211-$(CONFIG_NL80211) += nl80211.o
{
struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
int res;
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ bool have_band = false;
+ int i;
+
+ /* sanity check supported bands/channels */
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ sband = wiphy->bands[band];
+ if (!sband)
+ continue;
+
+ sband->band = band;
+
+ if (!sband->n_channels || !sband->n_bitrates) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < sband->n_channels; i++) {
+ sband->channels[i].orig_flags =
+ sband->channels[i].flags;
+ sband->channels[i].orig_mag =
+ sband->channels[i].max_antenna_gain;
+ sband->channels[i].orig_mpwr =
+ sband->channels[i].max_power;
+ sband->channels[i].band = band;
+ }
+
+ have_band = true;
+ }
+
+ if (!have_band) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ /* check and set up bitrates */
+ ieee80211_set_bitrate_flags(wiphy);
+
+ /* set up regulatory info */
+ wiphy_update_regulatory(wiphy);
mutex_lock(&cfg80211_drv_mutex);
extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
char *newname);
+void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
+void wiphy_update_regulatory(struct wiphy *wiphy);
+
#endif /* __NET_WIRELESS_CORE_H */
[NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_RATES },
+ [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
+ [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_MESH_ID_LEN },
+ [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
};
/* message building helper */
struct cfg80211_registered_device *dev)
{
void *hdr;
+ struct nlattr *nl_bands, *nl_band;
+ struct nlattr *nl_freqs, *nl_freq;
+ struct nlattr *nl_rates, *nl_rate;
+ enum ieee80211_band band;
+ struct ieee80211_channel *chan;
+ struct ieee80211_rate *rate;
+ int i;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
if (!hdr)
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+
+ nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
+ if (!nl_bands)
+ goto nla_put_failure;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (!dev->wiphy.bands[band])
+ continue;
+
+ nl_band = nla_nest_start(msg, band);
+ if (!nl_band)
+ goto nla_put_failure;
+
+ /* add frequencies */
+ nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
+ if (!nl_freqs)
+ goto nla_put_failure;
+
+ for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
+ nl_freq = nla_nest_start(msg, i);
+ if (!nl_freq)
+ goto nla_put_failure;
+
+ chan = &dev->wiphy.bands[band]->channels[i];
+ NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
+ chan->center_freq);
+
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
+ if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
+ if (chan->flags & IEEE80211_CHAN_NO_IBSS)
+ NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
+ if (chan->flags & IEEE80211_CHAN_RADAR)
+ NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
+
+ nla_nest_end(msg, nl_freq);
+ }
+
+ nla_nest_end(msg, nl_freqs);
+
+ /* add bitrates */
+ nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
+ if (!nl_rates)
+ goto nla_put_failure;
+
+ for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
+ nl_rate = nla_nest_start(msg, i);
+ if (!nl_rate)
+ goto nla_put_failure;
+
+ rate = &dev->wiphy.bands[band]->bitrates[i];
+ NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE,
+ rate->bitrate);
+ if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ NLA_PUT_FLAG(msg,
+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE);
+
+ nla_nest_end(msg, nl_rate);
+ }
+
+ nla_nest_end(msg, nl_rates);
+
+ nla_nest_end(msg, nl_band);
+ }
+ nla_nest_end(msg, nl_bands);
+
return genlmsg_end(msg, hdr);
nla_put_failure:
return -ENOBUFS;
}
+static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
+ [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
+ [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
+ [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
+ [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
+ [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
+};
+
+static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
+{
+ struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
+ int flag;
+
+ *mntrflags = 0;
+
+ if (!nla)
+ return -EINVAL;
+
+ if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
+ nla, mntr_flags_policy))
+ return -EINVAL;
+
+ for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
+ if (flags[flag])
+ *mntrflags |= (1<<flag);
+
+ return 0;
+}
+
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
+ struct vif_params params;
int err, ifindex;
enum nl80211_iftype type;
struct net_device *dev;
+ u32 flags;
+
+ memset(¶ms, 0, sizeof(params));
if (info->attrs[NL80211_ATTR_IFTYPE]) {
type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
goto unlock;
}
+ if (type == NL80211_IFTYPE_MESH_POINT &&
+ info->attrs[NL80211_ATTR_MESH_ID]) {
+ params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
+ params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+ }
+
rtnl_lock();
- err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
+ err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+ info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+ &flags);
+ err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
+ type, err ? NULL : &flags, ¶ms);
rtnl_unlock();
unlock:
static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
+ struct vif_params params;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
+ u32 flags;
+
+ memset(¶ms, 0, sizeof(params));
if (!info->attrs[NL80211_ATTR_IFNAME])
return -EINVAL;
goto unlock;
}
+ if (type == NL80211_IFTYPE_MESH_POINT &&
+ info->attrs[NL80211_ATTR_MESH_ID]) {
+ params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
+ params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+ }
+
rtnl_lock();
+ err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+ info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+ &flags);
err = drv->ops->add_virtual_intf(&drv->wiphy,
- nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
+ nla_data(info->attrs[NL80211_ATTR_IFNAME]),
+ type, err ? NULL : &flags, ¶ms);
rtnl_unlock();
+
unlock:
cfg80211_put_dev(drv);
return err;
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
int flags, struct net_device *dev,
- u8 *mac_addr, struct station_stats *stats)
+ u8 *mac_addr, struct station_info *sinfo)
{
void *hdr;
- struct nlattr *statsattr;
+ struct nlattr *sinfoattr;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
if (!hdr)
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
- statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
- if (!statsattr)
+ sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
+ if (!sinfoattr)
goto nla_put_failure;
- if (stats->filled & STATION_STAT_INACTIVE_TIME)
- NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
- stats->inactive_time);
- if (stats->filled & STATION_STAT_RX_BYTES)
- NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
- stats->rx_bytes);
- if (stats->filled & STATION_STAT_TX_BYTES)
- NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
- stats->tx_bytes);
-
- nla_nest_end(msg, statsattr);
+ if (sinfo->filled & STATION_INFO_INACTIVE_TIME)
+ NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME,
+ sinfo->inactive_time);
+ if (sinfo->filled & STATION_INFO_RX_BYTES)
+ NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES,
+ sinfo->rx_bytes);
+ if (sinfo->filled & STATION_INFO_TX_BYTES)
+ NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES,
+ sinfo->tx_bytes);
+ if (sinfo->filled & STATION_INFO_LLID)
+ NLA_PUT_U16(msg, NL80211_STA_INFO_LLID,
+ sinfo->llid);
+ if (sinfo->filled & STATION_INFO_PLID)
+ NLA_PUT_U16(msg, NL80211_STA_INFO_PLID,
+ sinfo->plid);
+ if (sinfo->filled & STATION_INFO_PLINK_STATE)
+ NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
+ sinfo->plink_state);
+
+ nla_nest_end(msg, sinfoattr);
return genlmsg_end(msg, hdr);
return genlmsg_cancel(msg, hdr);
}
+static int nl80211_dump_station(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ int wp_idx = 0;
+ int if_idx = 0;
+ int sta_idx = cb->args[2];
+ int wp_start = cb->args[0];
+ int if_start = cb->args[1];
+ struct station_info sinfo;
+ struct cfg80211_registered_device *dev;
+ struct wireless_dev *wdev;
+ u8 mac_addr[ETH_ALEN];
+ int err;
+ int exit = 0;
+
+ /* TODO: filter by device */
+ mutex_lock(&cfg80211_drv_mutex);
+ list_for_each_entry(dev, &cfg80211_drv_list, list) {
+ if (exit)
+ break;
+ if (++wp_idx < wp_start)
+ continue;
+ if_idx = 0;
+
+ mutex_lock(&dev->devlist_mtx);
+ list_for_each_entry(wdev, &dev->netdev_list, list) {
+ if (exit)
+ break;
+ if (++if_idx < if_start)
+ continue;
+ if (!dev->ops->dump_station)
+ continue;
+
+ for (;; ++sta_idx) {
+ rtnl_lock();
+ err = dev->ops->dump_station(&dev->wiphy,
+ wdev->netdev, sta_idx, mac_addr,
+ &sinfo);
+ rtnl_unlock();
+ if (err) {
+ sta_idx = 0;
+ break;
+ }
+ if (nl80211_send_station(skb,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ wdev->netdev, mac_addr,
+ &sinfo) < 0) {
+ exit = 1;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&dev->devlist_mtx);
+ }
+ mutex_unlock(&cfg80211_drv_mutex);
+
+ cb->args[0] = wp_idx;
+ cb->args[1] = if_idx;
+ cb->args[2] = sta_idx;
+
+ return skb->len;
+}
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
- struct station_stats stats;
+ struct station_info sinfo;
struct sk_buff *msg;
u8 *mac_addr = NULL;
- memset(&stats, 0, sizeof(stats));
+ memset(&sinfo, 0, sizeof(sinfo));
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
}
rtnl_lock();
- err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
+ err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo);
rtnl_unlock();
+ if (err)
+ goto out;
+
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
goto out;
if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
- dev, mac_addr, &stats) < 0)
+ dev, mac_addr, &sinfo) < 0)
goto out_free;
err = genlmsg_unicast(msg, info->snd_pid);
¶ms.station_flags))
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+ params.plink_action =
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
return err;
}
+static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
+ int flags, struct net_device *dev,
+ u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo)
+{
+ void *hdr;
+ struct nlattr *pinfoattr;
+
+ hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
+ if (!hdr)
+ return -1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
+ NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop);
+
+ pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
+ if (!pinfoattr)
+ goto nla_put_failure;
+ if (pinfo->filled & MPATH_INFO_FRAME_QLEN)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
+ pinfo->frame_qlen);
+ if (pinfo->filled & MPATH_INFO_DSN)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN,
+ pinfo->dsn);
+ if (pinfo->filled & MPATH_INFO_METRIC)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC,
+ pinfo->metric);
+ if (pinfo->filled & MPATH_INFO_EXPTIME)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME,
+ pinfo->exptime);
+ if (pinfo->filled & MPATH_INFO_FLAGS)
+ NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS,
+ pinfo->flags);
+ if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ pinfo->discovery_timeout);
+ if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES)
+ NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+ pinfo->discovery_retries);
+
+ nla_nest_end(msg, pinfoattr);
+
+ return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+ return genlmsg_cancel(msg, hdr);
+}
+
+static int nl80211_dump_mpath(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ int wp_idx = 0;
+ int if_idx = 0;
+ int sta_idx = cb->args[2];
+ int wp_start = cb->args[0];
+ int if_start = cb->args[1];
+ struct mpath_info pinfo;
+ struct cfg80211_registered_device *dev;
+ struct wireless_dev *wdev;
+ u8 dst[ETH_ALEN];
+ u8 next_hop[ETH_ALEN];
+ int err;
+ int exit = 0;
+
+ /* TODO: filter by device */
+ mutex_lock(&cfg80211_drv_mutex);
+ list_for_each_entry(dev, &cfg80211_drv_list, list) {
+ if (exit)
+ break;
+ if (++wp_idx < wp_start)
+ continue;
+ if_idx = 0;
+
+ mutex_lock(&dev->devlist_mtx);
+ list_for_each_entry(wdev, &dev->netdev_list, list) {
+ if (exit)
+ break;
+ if (++if_idx < if_start)
+ continue;
+ if (!dev->ops->dump_mpath)
+ continue;
+
+ for (;; ++sta_idx) {
+ rtnl_lock();
+ err = dev->ops->dump_mpath(&dev->wiphy,
+ wdev->netdev, sta_idx, dst,
+ next_hop, &pinfo);
+ rtnl_unlock();
+ if (err) {
+ sta_idx = 0;
+ break;
+ }
+ if (nl80211_send_mpath(skb,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ wdev->netdev, dst, next_hop,
+ &pinfo) < 0) {
+ exit = 1;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&dev->devlist_mtx);
+ }
+ mutex_unlock(&cfg80211_drv_mutex);
+
+ cb->args[0] = wp_idx;
+ cb->args[1] = if_idx;
+ cb->args[2] = sta_idx;
+
+ return skb->len;
+}
+
+static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct mpath_info pinfo;
+ struct sk_buff *msg;
+ u8 *dst = NULL;
+ u8 next_hop[ETH_ALEN];
+
+ memset(&pinfo, 0, sizeof(pinfo));
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->get_mpath) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
+ rtnl_unlock();
+
+ if (err)
+ goto out;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ goto out;
+
+ if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0,
+ dev, dst, next_hop, &pinfo) < 0)
+ goto out_free;
+
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto out;
+
+ out_free:
+ nlmsg_free(msg);
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 *dst = NULL;
+ u8 *next_hop = NULL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
+ return -EINVAL;
+
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->change_mpath) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 *dst = NULL;
+ u8 *next_hop = NULL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
+ return -EINVAL;
+
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->add_mpath) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 *dst = NULL;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->del_mpath) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->del_mpath(&drv->wiphy, dev, dst);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
{
.cmd = NL80211_CMD_GET_STATION,
.doit = nl80211_get_station,
- /* TODO: implement dumpit */
+ .dumpit = nl80211_dump_station,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_GET_MPATH,
+ .doit = nl80211_get_mpath,
+ .dumpit = nl80211_dump_mpath,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_SET_MPATH,
+ .doit = nl80211_set_mpath,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_NEW_MPATH,
+ .doit = nl80211_new_mpath,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_MPATH,
+ .doit = nl80211_del_mpath,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */
--- /dev/null
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This regulatory domain control implementation is highly incomplete, it
+ * only exists for the purpose of not regressing mac80211.
+ *
+ * For now, drivers can restrict the set of allowed channels by either
+ * not registering those channels or setting the IEEE80211_CHAN_DISABLED
+ * flag; that flag will only be *set* by this code, never *cleared.
+ *
+ * The usual implementation is for a driver to read a device EEPROM to
+ * determine which regulatory domain it should be operating under, then
+ * looking up the allowable channels in a driver-local table and finally
+ * registering those channels in the wiphy structure.
+ *
+ * Alternatively, drivers that trust the regulatory domain control here
+ * will register a complete set of capabilities and the control code
+ * will restrict the set by setting the IEEE80211_CHAN_* flags.
+ */
+#include <linux/kernel.h>
+#include <net/wireless.h>
+#include "core.h"
+
+static char *ieee80211_regdom = "US";
+module_param(ieee80211_regdom, charp, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
+
+struct ieee80211_channel_range {
+ short start_freq;
+ short end_freq;
+ int max_power;
+ int max_antenna_gain;
+ u32 flags;
+};
+
+struct ieee80211_regdomain {
+ const char *code;
+ const struct ieee80211_channel_range *ranges;
+ int n_ranges;
+};
+
+#define RANGE_PWR(_start, _end, _pwr, _ag, _flags) \
+ { _start, _end, _pwr, _ag, _flags }
+
+
+/*
+ * Ideally, in the future, these definitions will be loaded from a
+ * userspace table via some daemon.
+ */
+static const struct ieee80211_channel_range ieee80211_US_channels[] = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ RANGE_PWR(2412, 2462, 27, 6, 0),
+ /* IEEE 802.11a, channel 36*/
+ RANGE_PWR(5180, 5180, 23, 6, 0),
+ /* IEEE 802.11a, channel 40*/
+ RANGE_PWR(5200, 5200, 23, 6, 0),
+ /* IEEE 802.11a, channel 44*/
+ RANGE_PWR(5220, 5220, 23, 6, 0),
+ /* IEEE 802.11a, channels 48..64 */
+ RANGE_PWR(5240, 5320, 23, 6, 0),
+ /* IEEE 802.11a, channels 149..165, outdoor */
+ RANGE_PWR(5745, 5825, 30, 6, 0),
+};
+
+static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
+ /* IEEE 802.11b/g, channels 1..14 */
+ RANGE_PWR(2412, 2484, 20, 6, 0),
+ /* IEEE 802.11a, channels 34..48 */
+ RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
+ /* IEEE 802.11a, channels 52..64 */
+ RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_RADAR),
+};
+
+#define REGDOM(_code) \
+ { \
+ .code = __stringify(_code), \
+ .ranges = ieee80211_ ##_code## _channels, \
+ .n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \
+ }
+
+static const struct ieee80211_regdomain ieee80211_regdoms[] = {
+ REGDOM(US),
+ REGDOM(JP),
+};
+
+
+static const struct ieee80211_regdomain *get_regdom(void)
+{
+ static const struct ieee80211_channel_range
+ ieee80211_world_channels[] = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ RANGE_PWR(2412, 2462, 27, 6, 0),
+ };
+ static const struct ieee80211_regdomain regdom_world = REGDOM(world);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
+ if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
+ return &ieee80211_regdoms[i];
+
+ return ®dom_world;
+}
+
+
+static void handle_channel(struct ieee80211_channel *chan,
+ const struct ieee80211_regdomain *rd)
+{
+ int i;
+ u32 flags = chan->orig_flags;
+ const struct ieee80211_channel_range *rg = NULL;
+
+ for (i = 0; i < rd->n_ranges; i++) {
+ if (rd->ranges[i].start_freq <= chan->center_freq &&
+ chan->center_freq <= rd->ranges[i].end_freq) {
+ rg = &rd->ranges[i];
+ break;
+ }
+ }
+
+ if (!rg) {
+ /* not found */
+ flags |= IEEE80211_CHAN_DISABLED;
+ chan->flags = flags;
+ return;
+ }
+
+ chan->flags = flags;
+ chan->max_antenna_gain = min(chan->orig_mag,
+ rg->max_antenna_gain);
+ chan->max_power = min(chan->orig_mpwr, rg->max_power);
+}
+
+static void handle_band(struct ieee80211_supported_band *sband,
+ const struct ieee80211_regdomain *rd)
+{
+ int i;
+
+ for (i = 0; i < sband->n_channels; i++)
+ handle_channel(&sband->channels[i], rd);
+}
+
+void wiphy_update_regulatory(struct wiphy *wiphy)
+{
+ enum ieee80211_band band;
+ const struct ieee80211_regdomain *rd = get_regdom();
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+ if (wiphy->bands[band])
+ handle_band(wiphy->bands[band], rd);
+}
--- /dev/null
+/*
+ * Wireless utility functions
+ *
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <net/wireless.h>
+#include <asm/bitops.h>
+#include "core.h"
+
+int ieee80211_channel_to_frequency(int chan)
+{
+ if (chan < 14)
+ return 2407 + chan * 5;
+
+ if (chan == 14)
+ return 2484;
+
+ /* FIXME: 802.11j 17.3.8.3.2 */
+ return (chan + 1000) * 5;
+}
+EXPORT_SYMBOL(ieee80211_channel_to_frequency);
+
+int ieee80211_frequency_to_channel(int freq)
+{
+ if (freq == 2484)
+ return 14;
+
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+
+ /* FIXME: 802.11j 17.3.8.3.2 */
+ return freq/5 - 1000;
+}
+EXPORT_SYMBOL(ieee80211_frequency_to_channel);
+
+static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
+ enum ieee80211_band band)
+{
+ int i, want;
+
+ switch (band) {
+ case IEEE80211_BAND_5GHZ:
+ want = 3;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sband->bitrates[i].bitrate == 60 ||
+ sband->bitrates[i].bitrate == 120 ||
+ sband->bitrates[i].bitrate == 240) {
+ sband->bitrates[i].flags |=
+ IEEE80211_RATE_MANDATORY_A;
+ want--;
+ }
+ }
+ WARN_ON(want);
+ break;
+ case IEEE80211_BAND_2GHZ:
+ want = 7;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sband->bitrates[i].bitrate == 10) {
+ sband->bitrates[i].flags |=
+ IEEE80211_RATE_MANDATORY_B |
+ IEEE80211_RATE_MANDATORY_G;
+ want--;
+ }
+
+ if (sband->bitrates[i].bitrate == 20 ||
+ sband->bitrates[i].bitrate == 55 ||
+ sband->bitrates[i].bitrate == 110 ||
+ sband->bitrates[i].bitrate == 60 ||
+ sband->bitrates[i].bitrate == 120 ||
+ sband->bitrates[i].bitrate == 240) {
+ sband->bitrates[i].flags |=
+ IEEE80211_RATE_MANDATORY_G;
+ want--;
+ }
+
+ if (sband->bitrates[i].bitrate != 10 &&
+ sband->bitrates[i].bitrate != 20 &&
+ sband->bitrates[i].bitrate != 55 &&
+ sband->bitrates[i].bitrate != 110)
+ sband->bitrates[i].flags |=
+ IEEE80211_RATE_ERP_G;
+ }
+ WARN_ON(want != 0 && want != 3 && want != 6);
+ break;
+ case IEEE80211_NUM_BANDS:
+ WARN_ON(1);
+ break;
+ }
+}
+
+void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
+{
+ enum ieee80211_band band;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+ if (wiphy->bands[band])
+ set_mandatory_flags_band(wiphy->bands[band], band);
+}
static DEFINE_RWLOCK(xfrm_policy_lock);
+static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX];
unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
EXPORT_SYMBOL(xfrm_policy_count);
policy = kzalloc(sizeof(struct xfrm_policy), gfp);
if (policy) {
+ INIT_LIST_HEAD(&policy->bytype);
INIT_HLIST_NODE(&policy->bydst);
INIT_HLIST_NODE(&policy->byidx);
rwlock_init(&policy->lock);
if (del_timer(&policy->timer))
BUG();
+ write_lock_bh(&xfrm_policy_lock);
+ list_del(&policy->bytype);
+ write_unlock_bh(&xfrm_policy_lock);
+
security_xfrm_policy_free(policy);
kfree(policy);
}
policy->curlft.use_time = 0;
if (!mod_timer(&policy->timer, jiffies + HZ))
xfrm_pol_hold(policy);
+ list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]);
write_unlock_bh(&xfrm_policy_lock);
if (delpol)
}
EXPORT_SYMBOL(xfrm_policy_flush);
-int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*),
+int xfrm_policy_walk(struct xfrm_policy_walk *walk,
+ int (*func)(struct xfrm_policy *, int, int, void*),
void *data)
{
- struct xfrm_policy *pol, *last = NULL;
- struct hlist_node *entry;
- int dir, last_dir = 0, count, error;
+ struct xfrm_policy *old, *pol, *last = NULL;
+ int error = 0;
+
+ if (walk->type >= XFRM_POLICY_TYPE_MAX &&
+ walk->type != XFRM_POLICY_TYPE_ANY)
+ return -EINVAL;
+ if (walk->policy == NULL && walk->count != 0)
+ return 0;
+
+ old = pol = walk->policy;
+ walk->policy = NULL;
read_lock_bh(&xfrm_policy_lock);
- count = 0;
- for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
- struct hlist_head *table = xfrm_policy_bydst[dir].table;
- int i;
+ for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) {
+ if (walk->type != walk->cur_type &&
+ walk->type != XFRM_POLICY_TYPE_ANY)
+ continue;
- hlist_for_each_entry(pol, entry,
- &xfrm_policy_inexact[dir], bydst) {
- if (pol->type != type)
+ if (pol == NULL) {
+ pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type],
+ struct xfrm_policy, bytype);
+ }
+ list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) {
+ if (pol->dead)
continue;
if (last) {
- error = func(last, last_dir % XFRM_POLICY_MAX,
- count, data);
- if (error)
+ error = func(last, xfrm_policy_id2dir(last->index),
+ walk->count, data);
+ if (error) {
+ xfrm_pol_hold(last);
+ walk->policy = last;
goto out;
- }
- last = pol;
- last_dir = dir;
- count++;
- }
- for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
- hlist_for_each_entry(pol, entry, table + i, bydst) {
- if (pol->type != type)
- continue;
- if (last) {
- error = func(last, last_dir % XFRM_POLICY_MAX,
- count, data);
- if (error)
- goto out;
}
- last = pol;
- last_dir = dir;
- count++;
}
+ last = pol;
+ walk->count++;
}
+ pol = NULL;
}
- if (count == 0) {
+ if (walk->count == 0) {
error = -ENOENT;
goto out;
}
- error = func(last, last_dir % XFRM_POLICY_MAX, 0, data);
+ if (last)
+ error = func(last, xfrm_policy_id2dir(last->index), 0, data);
out:
read_unlock_bh(&xfrm_policy_lock);
+ if (old != NULL)
+ xfrm_pol_put(old);
return error;
}
EXPORT_SYMBOL(xfrm_policy_walk);
panic("XFRM: failed to allocate bydst hash\n");
}
+ for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++)
+ INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
+
INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
register_netdevice_notifier(&xfrm_dev_notifier);
}
* Main use is finding SA after policy selected tunnel or transport mode.
* Also, it can be used by ah/esp icmp error handler to find offending SA.
*/
+static LIST_HEAD(xfrm_state_all);
static struct hlist_head *xfrm_state_bydst __read_mostly;
static struct hlist_head *xfrm_state_bysrc __read_mostly;
static struct hlist_head *xfrm_state_byspi __read_mostly;
if (x) {
atomic_set(&x->refcnt, 1);
atomic_set(&x->tunnel_users, 0);
+ INIT_LIST_HEAD(&x->all);
INIT_HLIST_NODE(&x->bydst);
INIT_HLIST_NODE(&x->bysrc);
INIT_HLIST_NODE(&x->byspi);
{
BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
+ spin_lock_bh(&xfrm_state_lock);
+ list_del(&x->all);
+ spin_unlock_bh(&xfrm_state_lock);
+
spin_lock_bh(&xfrm_state_gc_lock);
hlist_add_head(&x->bydst, &xfrm_state_gc_list);
spin_unlock_bh(&xfrm_state_gc_lock);
x->genid = ++xfrm_state_genid;
+ list_add_tail(&x->all, &xfrm_state_all);
+
h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
x->props.reqid, x->props.family);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
}
EXPORT_SYMBOL(xfrm_alloc_spi);
-int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
+int xfrm_state_walk(struct xfrm_state_walk *walk,
+ int (*func)(struct xfrm_state *, int, void*),
void *data)
{
- int i;
- struct xfrm_state *x, *last = NULL;
- struct hlist_node *entry;
- int count = 0;
+ struct xfrm_state *old, *x, *last = NULL;
int err = 0;
+ if (walk->state == NULL && walk->count != 0)
+ return 0;
+
+ old = x = walk->state;
+ walk->state = NULL;
spin_lock_bh(&xfrm_state_lock);
- for (i = 0; i <= xfrm_state_hmask; i++) {
- hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
- if (!xfrm_id_proto_match(x->id.proto, proto))
- continue;
- if (last) {
- err = func(last, count, data);
- if (err)
- goto out;
+ if (x == NULL)
+ x = list_first_entry(&xfrm_state_all, struct xfrm_state, all);
+ list_for_each_entry_from(x, &xfrm_state_all, all) {
+ if (x->km.state == XFRM_STATE_DEAD)
+ continue;
+ if (!xfrm_id_proto_match(x->id.proto, walk->proto))
+ continue;
+ if (last) {
+ err = func(last, walk->count, data);
+ if (err) {
+ xfrm_state_hold(last);
+ walk->state = last;
+ goto out;
}
- last = x;
- count++;
}
+ last = x;
+ walk->count++;
}
- if (count == 0) {
+ if (walk->count == 0) {
err = -ENOENT;
goto out;
}
- err = func(last, 0, data);
+ if (last)
+ err = func(last, 0, data);
out:
spin_unlock_bh(&xfrm_state_lock);
+ if (old != NULL)
+ xfrm_state_put(old);
return err;
}
EXPORT_SYMBOL(xfrm_state_walk);
struct sk_buff *out_skb;
u32 nlmsg_seq;
u16 nlmsg_flags;
- int start_idx;
- int this_idx;
};
static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
struct nlmsghdr *nlh;
int err;
- if (sp->this_idx < sp->start_idx)
- goto out;
-
nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
if (nlh == NULL)
goto nla_put_failure;
nlmsg_end(skb, nlh);
-out:
- sp->this_idx++;
return 0;
nla_put_failure:
return err;
}
+static int xfrm_dump_sa_done(struct netlink_callback *cb)
+{
+ struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
+ xfrm_state_walk_done(walk);
+ return 0;
+}
+
static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
{
+ struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
struct xfrm_dump_info info;
+ BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
+ sizeof(cb->args) - sizeof(cb->args[0]));
+
info.in_skb = cb->skb;
info.out_skb = skb;
info.nlmsg_seq = cb->nlh->nlmsg_seq;
info.nlmsg_flags = NLM_F_MULTI;
- info.this_idx = 0;
- info.start_idx = cb->args[0];
- (void) xfrm_state_walk(0, dump_one_state, &info);
- cb->args[0] = info.this_idx;
+
+ if (!cb->args[0]) {
+ cb->args[0] = 1;
+ xfrm_state_walk_init(walk, 0);
+ }
+
+ (void) xfrm_state_walk(walk, dump_one_state, &info);
return skb->len;
}
info.out_skb = skb;
info.nlmsg_seq = seq;
info.nlmsg_flags = 0;
- info.this_idx = info.start_idx = 0;
if (dump_one_state(x, 0, &info)) {
kfree_skb(skb);
struct sk_buff *skb = sp->out_skb;
struct nlmsghdr *nlh;
- if (sp->this_idx < sp->start_idx)
- goto out;
-
nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
if (nlh == NULL)
goto nlmsg_failure;
nlmsg_end(skb, nlh);
-out:
- sp->this_idx++;
return 0;
nlmsg_failure:
return -EMSGSIZE;
}
+static int xfrm_dump_policy_done(struct netlink_callback *cb)
+{
+ struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
+
+ xfrm_policy_walk_done(walk);
+ return 0;
+}
+
static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
{
+ struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
struct xfrm_dump_info info;
+ BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) >
+ sizeof(cb->args) - sizeof(cb->args[0]));
+
info.in_skb = cb->skb;
info.out_skb = skb;
info.nlmsg_seq = cb->nlh->nlmsg_seq;
info.nlmsg_flags = NLM_F_MULTI;
- info.this_idx = 0;
- info.start_idx = cb->args[0];
- (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info);
-#ifdef CONFIG_XFRM_SUB_POLICY
- (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info);
-#endif
- cb->args[0] = info.this_idx;
+
+ if (!cb->args[0]) {
+ cb->args[0] = 1;
+ xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
+ }
+
+ (void) xfrm_policy_walk(walk, dump_one_policy, &info);
return skb->len;
}
info.out_skb = skb;
info.nlmsg_seq = seq;
info.nlmsg_flags = 0;
- info.this_idx = info.start_idx = 0;
if (dump_one_policy(xp, dir, 0, &info) < 0) {
kfree_skb(skb);
static struct xfrm_link {
int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
int (*dump)(struct sk_buff *, struct netlink_callback *);
+ int (*done)(struct netlink_callback *);
} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
[XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },
[XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
- .dump = xfrm_dump_sa },
+ .dump = xfrm_dump_sa,
+ .done = xfrm_dump_sa_done },
[XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy },
[XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy },
[XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
- .dump = xfrm_dump_policy },
+ .dump = xfrm_dump_policy,
+ .done = xfrm_dump_policy_done },
[XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
[XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire },
[XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
if (link->dump == NULL)
return -EINVAL;
- return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL);
+ return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done);
}
err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,